<commit_before>/** @file
    @brief Header

    @date 2016

    @author
    Sensics, Inc.
    <http://sensics.com>

*/

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

#ifndef INCLUDED_UVCImageSource_cpp_GUID_2563F019_11B6_4F61_9E8C_C3ED2A573AF6
#define INCLUDED_UVCImageSource_cpp_GUID_2563F019_11B6_4F61_9E8C_C3ED2A573AF6

// Internal Includes
#include "ImageSource.h"
#include "ImageSourceFactories.h"

// Library/third-party includes
#include <libuvc/libuvc.h>
#include <opencv2/core/core_c.h>

// Standard includes
#include <memory>
#include <stdexcept>
#include <string>
#include <iostream>
#include <cstdio>
#include <unistd.h>
#include <mutex>

namespace osvr {
namespace vbtracker {
    class UVCImageSource : public ImageSource {
      public:
        /// Constructor
        UVCImageSource(int vendor_id = 0, int product_id = 0, const char* serial_number = nullptr);

        /// Destructor
        virtual ~UVCImageSource();

        /// @return true if the camera/image source is OK
        virtual bool ok() const override;

        /// Trigger camera capture. May not necessarily include retrieval.
        /// Blocks until an image is available. or failure occurs.
        ///
        /// Timestamp after this call returns.
        ///
        /// @return false if the camera failed.
        virtual bool grab() override;

        /// Get resolution of the images from this source.
        virtual cv::Size resolution() const override;

        /// For those devices that naturally read a non-corrupt color image,
        /// overriding just this method will let the default implementation of
        /// retrieve() do the RGB to Gray for you.
        virtual void retrieveColor(cv::Mat &color) override;

      protected:
        /// This callback function is called each time a new frame is received
        /// from the video stream.
        //@{
        static void callback(uvc_frame_t *frame, void *ptr);
        void callback(uvc_frame_t *frame);
        //@}

      private:
        uvc_context_t* uvcContext_;
        uvc_device_t* camera_;
        uvc_device_handle_t* cameraHandle_;
        uvc_stream_ctrl_t streamControl_;

        cv::Size resolution_;       //< resolution of camera
        uvc_frame_t* frame_;        //< raw UVC frame

        std::mutex mutex_;          //< to protect frame_
    };

    using UVCImageSourcePtr = std::unique_ptr<UVCImageSource>;

    UVCImageSource::UVCImageSource(int vendor_id, int product_id, const char* serial_number) :
        uvcContext_{nullptr}, camera_{nullptr}, cameraHandle_{nullptr}, streamControl_{}, resolution_{0, 0}, frame_{nullptr}
    {
        // TODO

        // Initialize the libuvc context
        const auto init_res = uvc_init(&uvcContext_, nullptr);
        if (UVC_SUCCESS != init_res) {
            throw std::runtime_error("Error initializing UVC context: " + std::string(uvc_strerror(init_res)));
        }

        // Find the requested camera
        const auto find_res = uvc_find_device(uvcContext_, &camera_, vendor_id, product_id, serial_number);
        if (UVC_SUCCESS != find_res) {
            uvc_exit(uvcContext_);
            throw std::runtime_error("Error finding requested camera: " + std::string(uvc_strerror(find_res)));
        }

        // Try to open the device -- requires exclusive access
        const auto open_res = uvc_open(camera_, &cameraHandle_);
        if (UVC_SUCCESS != open_res) {
            uvc_unref_device(camera_);
            uvc_exit(uvcContext_);
            throw std::runtime_error("Error opening camera: " + std::string(uvc_strerror(open_res)));
        }
        //uvc_print_diag(cameraHandle_, stdout);

        // Setup streaming parameters
        const int resolution_x = 640; // pixels
        const int resolution_y = 480; // pixels
        resolution_ = cvSize(resolution_x, resolution_y);
        const int frame_rate = 100; // fps
        const auto setup_res = uvc_get_stream_ctrl_format_size(cameraHandle_,
                                                               &streamControl_,
                                                               UVC_FRAME_FORMAT_MJPEG,
                                                               resolution_x,
                                                               resolution_y,
                                                               frame_rate);
        //uvc_print_stream_ctrl(&streamControl_, stdout);
        if (UVC_SUCCESS != setup_res) {
            std::cerr << "Error setting up requested stream format. "
                + std::string(uvc_strerror(setup_res));
        }

        // Start streaming video.
        const auto stream_res = uvc_start_streaming(cameraHandle_, &streamControl_, &UVCImageSource::callback, this, 0);
        if (UVC_SUCCESS != stream_res) {
            uvc_close(cameraHandle_);
            uvc_unref_device(camera_);
            uvc_exit(uvcContext_);
            throw std::runtime_error("Error streaming from camera: " + std::string(uvc_strerror(stream_res)));
        }

    }

    UVCImageSource::~UVCImageSource()
    {
        // Stop streaming video
        uvc_stop_streaming(cameraHandle_);

        // Release our handle on the camera
        uvc_close(cameraHandle_);

        // Release the device descriptor
        uvc_unref_device(camera_);

        // Close the UVC context. This closes and cleans up any existing device
        // handles, and it closes the libusb context if one was not provided
        uvc_exit(uvcContext_);
    }

    bool UVCImageSource::ok() const
    {
        // TODO
        return true;
    }

    bool UVCImageSource::grab()
    {
        // libuvc doesn't provide for separate grab() and retrieve() operations.
        // Instead, grab() will set a flag to alert the callback function that
        // we wish to store the next frame and retrieve() will return that
        // frame.
        std::lock_guard<std::mutex> guard(mutex_);
        return (frame_ != nullptr);
    }

    cv::Size UVCImageSource::resolution() const
    {
        return resolution_;
    }

    void UVCImageSource::retrieveColor(cv::Mat &color)
    {
        // libuvc doesn't provide for separate grab() and retrieve() operations.
        // Instead, grab() will set a flag to alert the callback function that
        // we wish to store the next frame and retrieve() will return that
        // frame.

        std::lock_guard<std::mutex> guard(mutex_);

        if (!frame_) {
            throw std::runtime_error("Error: There's no frame available.");
        }

        // We'll convert the image from YUV/JPEG to rgb, so allocate space
        auto rgb = uvc_allocate_frame(frame_->width * frame_->height * 3);
        if (!rgb) {
            throw std::runtime_error("Error: Unable to allocate the rgb frame.");
        }

        // Do the rgb conversion
        auto convert_ret = uvc_mjpeg2rgb(frame_, rgb);
        if (UVC_SUCCESS != convert_ret) {
            // Try any2rgb() instead
            auto any_ret = uvc_any2rgb(frame_, rgb);
            if (UVC_SUCCESS != any_ret) {
                uvc_free_frame(rgb);
                throw std::runtime_error("Error: Unable to convert frame to rgb: " + std::string(uvc_strerror(convert_ret)));
            }
        }

        // Convert the image to at cv::Mat
        color = cv::Mat(rgb->height, rgb->width, CV_8UC3, rgb->data).clone();

        uvc_free_frame(rgb);
    }

    void UVCImageSource::callback(uvc_frame_t *frame, void *ptr)
    {
        auto me = static_cast<UVCImageSource*>(ptr);
        me->callback(frame);
    }

    void UVCImageSource::callback(uvc_frame_t *frame)
    {
        // Just copy the UVC frame to keep things quick. We'll do any conversion
        // upon request in the retrieveColor() method.
        std::lock_guard<std::mutex> guard(mutex_);
        if (frame_)
            uvc_free_frame(frame_);
        frame_ = uvc_allocate_frame(frame->data_bytes);
        uvc_duplicate_frame(frame, frame_);
    }

    /// Factory method to open a USB video class (UVC) device as an image
    /// source.
    ImageSourcePtr openUVCCamera(int vendor_id, int product_id, const char* serial_number)
    {
        auto ret = ImageSourcePtr{};
        try {
            auto source = new UVCImageSource(vendor_id, product_id, serial_number);
            ret.reset(source);
        } catch (const std::exception& e) {
            std::cerr << "Caught exception initializing UVC camera image source: " << e.what() << std::endl;
        }
        return ret;
    }

    /// Factory method to open the HDK camera as an image source via libuvc.
    ImageSourcePtr openHDKCameraUVC()
    {
        const int vendor_id = 0x0bda;
        const int product_id = 0x57e8;
        return openUVCCamera(vendor_id, product_id);
    }

} // namespace vbtracker
} // namespace osvr

#endif // INCLUDED_UVCImageSource_cpp_GUID_2563F019_11B6_4F61_9E8C_C3ED2A573AF6

<commit_msg>Added slight buffering to UVCImageSource which fixes dropped frames due to races between the camera and processing threads.<commit_after>/** @file
    @brief Header

    @date 2016

    @author
    Sensics, Inc.
    <http://sensics.com>

*/

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

#ifndef INCLUDED_UVCImageSource_cpp_GUID_2563F019_11B6_4F61_9E8C_C3ED2A573AF6
#define INCLUDED_UVCImageSource_cpp_GUID_2563F019_11B6_4F61_9E8C_C3ED2A573AF6

// Internal Includes
#include "ImageSource.h"
#include "ImageSourceFactories.h"

// Library/third-party includes
#include <libuvc/libuvc.h>
#include <opencv2/core/core_c.h>

// Standard includes
#include <memory>
#include <stdexcept>
#include <string>
#include <iostream>
#include <cstdio>
#include <unistd.h>
#include <mutex>
#include <condition_variable>
#include <queue>

namespace osvr {
namespace vbtracker {
    class UVCImageSource : public ImageSource {
      public:
        /// Constructor
        UVCImageSource(int vendor_id = 0, int product_id = 0, const char* serial_number = nullptr);

        /// Destructor
        virtual ~UVCImageSource();

        /// @return true if the camera/image source is OK
        virtual bool ok() const override;

        /// Trigger camera capture. May not necessarily include retrieval.
        /// Blocks until an image is available. or failure occurs.
        ///
        /// Timestamp after this call returns.
        ///
        /// @return false if the camera failed.
        virtual bool grab() override;

        /// Get resolution of the images from this source.
        virtual cv::Size resolution() const override;

        /// For those devices that naturally read a non-corrupt color image,
        /// overriding just this method will let the default implementation of
        /// retrieve() do the RGB to Gray for you.
        virtual void retrieveColor(cv::Mat &color) override;

      protected:
        /// This callback function is called each time a new frame is received
        /// from the video stream.
        //@{
        static void callback(uvc_frame_t *frame, void *ptr);
        void callback(uvc_frame_t *frame);
        //@}

      private:
        uvc_context_t* uvcContext_;
        uvc_device_t* camera_;
        uvc_device_handle_t* cameraHandle_;
        uvc_stream_ctrl_t streamControl_;

        cv::Size resolution_;       //< resolution of camera
        std::queue<uvc_frame_t*> frames_; //< raw UVC frames

        std::mutex mutex_;          //< to protect frames_
        std::condition_variable frames_available_; //< To allo grab() to wait for frames to become available
    };

    using UVCImageSourcePtr = std::unique_ptr<UVCImageSource>;

    UVCImageSource::UVCImageSource(int vendor_id, int product_id, const char* serial_number) :
        uvcContext_{nullptr}, camera_{nullptr}, cameraHandle_{nullptr}, streamControl_{}, resolution_{0, 0}
    {
        // TODO

        // Initialize the libuvc context
        const auto init_res = uvc_init(&uvcContext_, nullptr);
        if (UVC_SUCCESS != init_res) {
            throw std::runtime_error("Error initializing UVC context: " + std::string(uvc_strerror(init_res)));
        }

        // Find the requested camera
        const auto find_res = uvc_find_device(uvcContext_, &camera_, vendor_id, product_id, serial_number);
        if (UVC_SUCCESS != find_res) {
            uvc_exit(uvcContext_);
            throw std::runtime_error("Error finding requested camera: " + std::string(uvc_strerror(find_res)));
        }

        // Try to open the device -- requires exclusive access
        const auto open_res = uvc_open(camera_, &cameraHandle_);
        if (UVC_SUCCESS != open_res) {
            uvc_unref_device(camera_);
            uvc_exit(uvcContext_);
            throw std::runtime_error("Error opening camera: " + std::string(uvc_strerror(open_res)));
        }
        //uvc_print_diag(cameraHandle_, stdout);

        // Setup streaming parameters
        const int resolution_x = 640; // pixels
        const int resolution_y = 480; // pixels
        resolution_ = cvSize(resolution_x, resolution_y);
        const int frame_rate = 100; // fps
        const auto setup_res = uvc_get_stream_ctrl_format_size(cameraHandle_,
                                                               &streamControl_,
                                                               UVC_FRAME_FORMAT_MJPEG,
                                                               resolution_x,
                                                               resolution_y,
                                                               frame_rate);
        //uvc_print_stream_ctrl(&streamControl_, stdout);
        if (UVC_SUCCESS != setup_res) {
            std::cerr << "Error setting up requested stream format. "
                + std::string(uvc_strerror(setup_res));
        }

        // Start streaming video.
        const auto stream_res = uvc_start_streaming(cameraHandle_, &streamControl_, &UVCImageSource::callback, this, 0);
        if (UVC_SUCCESS != stream_res) {
            uvc_close(cameraHandle_);
            uvc_unref_device(camera_);
            uvc_exit(uvcContext_);
            throw std::runtime_error("Error streaming from camera: " + std::string(uvc_strerror(stream_res)));
        }

    }

    UVCImageSource::~UVCImageSource()
    {
        // Stop streaming video
        uvc_stop_streaming(cameraHandle_);

        // Release our handle on the camera
        uvc_close(cameraHandle_);

        // Release the device descriptor
        uvc_unref_device(camera_);

        // Close the UVC context. This closes and cleans up any existing device
        // handles, and it closes the libusb context if one was not provided
        uvc_exit(uvcContext_);
    }

    bool UVCImageSource::ok() const
    {
        // TODO
        return true;
    }

    bool UVCImageSource::grab()
    {
      //Gain access to frames_ queue
      std::unique_lock<std::mutex> lock(mutex_);

      //Check if there are any frames available
      if (frames_.empty())
	//Wait for some frames to become available
	frames_available_.wait(lock);

      //Good to go!
      return !frames_.empty();
    }

    cv::Size UVCImageSource::resolution() const
    {
        return resolution_;
    }

    void UVCImageSource::retrieveColor(cv::Mat &color)
    {
        uvc_frame_t* current_frame;

        {
	    //Grab a frame from the queue, but don't keep the queue locked!
	    std::lock_guard<std::mutex> lock(mutex_);

	    if (frames_.empty()) {
	      throw std::runtime_error("Error: There's no frames available.");
	    }

	    current_frame = frames_.front();
	    frames_.pop();
        };

        // We'll convert the image from YUV/JPEG to rgb, so allocate space
        auto rgb = uvc_allocate_frame(current_frame->width * current_frame->height * 3);
        if (!rgb) {
            throw std::runtime_error("Error: Unable to allocate the rgb frame.");
        }

        // Do the rgb conversion
        auto convert_ret = uvc_mjpeg2rgb(current_frame, rgb);
        if (UVC_SUCCESS != convert_ret) {
            // Try any2rgb() instead
            auto any_ret = uvc_any2rgb(current_frame, rgb);
            if (UVC_SUCCESS != any_ret) {
                uvc_free_frame(rgb);
                throw std::runtime_error("Error: Unable to convert frame to rgb: " + std::string(uvc_strerror(convert_ret)));
            }
        }

        // Convert the image to at cv::Mat
        color = cv::Mat(rgb->height, rgb->width, CV_8UC3, rgb->data).clone();

        uvc_free_frame(current_frame);
        uvc_free_frame(rgb);
    }

    void UVCImageSource::callback(uvc_frame_t *frame, void *ptr)
    {
        auto me = static_cast<UVCImageSource*>(ptr);
        me->callback(frame);
    }

    void UVCImageSource::callback(uvc_frame_t *frame)
    {
        // Just copy the UVC frame to keep things quick (cannot drop
        // frames or we'll lose tracking!). We'll do any conversion
        // upon request in the retrieveColor() method.

        //Copy the frame, then look for the lock
        uvc_frame_t* copied_frame = uvc_allocate_frame(frame->data_bytes);
        uvc_duplicate_frame(frame, copied_frame);

        std::lock_guard<std::mutex> lock(mutex_);
	frames_.push(copied_frame);
	if (frames_.size() > 100) {
	  std::cerr << "WARNING! Dropping frames from video tracker as they are not being processed fast enough! This will disrupt tracking.";
	  while (!frames_.empty()) {
	    uvc_free_frame(frames_.front());
	    frames_.pop();
	  }
	}
	frames_available_.notify_one();
    }

    /// Factory method to open a USB video class (UVC) device as an image
    /// source.
    ImageSourcePtr openUVCCamera(int vendor_id, int product_id, const char* serial_number)
    {
        auto ret = ImageSourcePtr{};
        try {
            auto source = new UVCImageSource(vendor_id, product_id, serial_number);
            ret.reset(source);
        } catch (const std::exception& e) {
            std::cerr << "Caught exception initializing UVC camera image source: " << e.what() << std::endl;
        }
        return ret;
    }

    /// Factory method to open the HDK camera as an image source via libuvc.
    ImageSourcePtr openHDKCameraUVC()
    {
        const int vendor_id = 0x0bda;
        const int product_id = 0x57e8;
        return openUVCCamera(vendor_id, product_id);
    }

} // namespace vbtracker
} // namespace osvr

#endif // INCLUDED_UVCImageSource_cpp_GUID_2563F019_11B6_4F61_9E8C_C3ED2A573AF6

<|endoftext|>


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

/*
 * $Id$
 */

#include <windows.h>

#include <xercesc/util/FileManagers/WindowsFileMgr.hpp>
#include <xercesc/util/Janitor.hpp>
#include <xercesc/util/XMLString.hpp>
#include <xercesc/util/XMLUniDefs.hpp>

XERCES_CPP_NAMESPACE_BEGIN

static bool isBackSlash(XMLCh c) {
    return c == chBackSlash ||
           c == chYenSign   ||
           c == chWonSign;
}

WindowsFileMgr::WindowsFileMgr()
{
    // Figure out if we are on NT and save that flag for later use
    OSVERSIONINFO   OSVer;
    OSVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
    ::GetVersionEx(&OSVer);
    _onNT = (OSVer.dwPlatformId == VER_PLATFORM_WIN32_NT);
}

WindowsFileMgr::~WindowsFileMgr()
{
}

FileHandle
WindowsFileMgr::open(const XMLCh* fileName, bool toWrite, MemoryManager* const manager)
{
    // Watch for obvious wierdness
    if (!fileName)
        return 0;

    //
    //  We have to play a little trick here. If its /x:.....
    //  style fully qualified path, we have to toss the leading /
    //  character.
    //
    const XMLCh* nameToOpen = fileName;
    if (*fileName == chForwardSlash)
    {
        if (XMLString::stringLen(fileName) > 3)
        {
            if (*(fileName + 2) == chColon)
            {
                const XMLCh chDrive = *(fileName + 1);
                if (((chDrive >= chLatin_A) && (chDrive <= chLatin_Z))
                ||  ((chDrive >= chLatin_a) && (chDrive <= chLatin_z)))
                {
                    nameToOpen = fileName + 1;
                }
            }

            // Similarly for UNC paths
            if ( *(fileName + 1) == *(fileName + 2) &&
                 (*(fileName + 1) == chForwardSlash ||
                  *(fileName + 1) == chBackSlash) )
            {
                nameToOpen = fileName + 1;
            }
        }
    }

    //  Ok, this might look stupid but its a semi-expedient way to deal
    //  with a thorny problem. Shift-JIS and some other Asian encodings
    //  are fundamentally broken and map both the backslash and the Yen
    //  sign to the same code point. Transcoders have to pick one or the
    //  other to map '\' to Unicode and tend to choose the Yen sign.
    //
    //  Unicode Yen or Won signs as directory separators will fail.
    //
    //  So, we will check this path name for Yen or won signs and, if they are
    //  there, we'll replace them with slashes.
    //
    //  A further twist:  we replace Yen and Won with forward slashes rather
    //   than back slashes.  Either form of slash will work as a directory
    //   separator.  On Win 95 and 98, though, Unicode back-slashes may
    //   fail to transode back to 8-bit 0x5C with some Unicode converters
    //   to  some of the problematic code pages.  Forward slashes always
    //   transcode correctly back to 8 bit char * form.
    //
    XMLCh *tmpUName = 0;

    const XMLCh* srcPtr = nameToOpen;
    while (*srcPtr)
    {
        if (*srcPtr == chYenSign ||
            *srcPtr == chWonSign)
            break;
        srcPtr++;
    }

    //
    //  If we found a yen, then we have to create a temp file name. Else
    //  go with the file name as is and save the overhead.
    //
    if (*srcPtr)
    {
        tmpUName = XMLString::replicate(nameToOpen, manager);

        XMLCh* tmpPtr = tmpUName;
        while (*tmpPtr)
        {
            if (*tmpPtr == chYenSign ||
                *tmpPtr == chWonSign)
                *tmpPtr = chForwardSlash;
            tmpPtr++;
        }
        nameToOpen = tmpUName;
    }
    FileHandle retVal = 0;
    if (_onNT)
    {
        retVal = ::CreateFileW
            (
            (LPCWSTR) nameToOpen
            , toWrite?GENERIC_WRITE:GENERIC_READ
            , FILE_SHARE_READ
            , 0
            , toWrite?CREATE_ALWAYS:OPEN_EXISTING
            , toWrite?FILE_ATTRIBUTE_NORMAL:FILE_FLAG_SEQUENTIAL_SCAN
            , 0
            );
    }
    else
    {
        //
        //  We are Win 95 / 98.  Take the Unicode file name back to (char *)
        //    so that we can open it.
        //
        char* tmpName = XMLString::transcode(nameToOpen, manager);
        retVal = ::CreateFileA
            (
            tmpName
            , toWrite?GENERIC_WRITE:GENERIC_READ
            , FILE_SHARE_READ
            , 0
            , toWrite?CREATE_ALWAYS:OPEN_EXISTING
            , toWrite?FILE_ATTRIBUTE_NORMAL:FILE_FLAG_SEQUENTIAL_SCAN
            , 0
            );
        manager->deallocate(tmpName);//delete [] tmpName;
    }

    if (tmpUName)
        manager->deallocate(tmpUName);//delete [] tmpUName;

    if (retVal == INVALID_HANDLE_VALUE)
        return 0;

    return retVal;
}

FileHandle
WindowsFileMgr::open(const char* path, bool toWrite, MemoryManager* const manager)
{
    FileHandle retVal = ::CreateFileA
    (
        path
        , toWrite?GENERIC_WRITE:GENERIC_READ
        , FILE_SHARE_READ
        , 0
        , toWrite?OPEN_ALWAYS:OPEN_EXISTING
        , toWrite?FILE_ATTRIBUTE_NORMAL:FILE_FLAG_SEQUENTIAL_SCAN
        , 0
    );

    if (retVal == INVALID_HANDLE_VALUE)
        return 0;

    return retVal;
}

FileHandle
WindowsFileMgr::openStdIn(MemoryManager* const manager)
{
    //
    //  Get the standard input handle. Duplicate it and return that copy
    //  since the outside world cannot tell the difference and will shut
    //  down this handle when its done with it. If we gave out the orignal,
    //  shutting it would prevent any further output.
    //
    HANDLE stdInOrg = ::GetStdHandle(STD_INPUT_HANDLE);
    if (stdInOrg == INVALID_HANDLE_VALUE) {
        XMLCh stdinStr[] = {chLatin_s, chLatin_t, chLatin_d, chLatin_i, chLatin_n, chNull};
        ThrowXMLwithMemMgr1(XMLPlatformUtilsException, XMLExcepts::File_CouldNotOpenFile, stdinStr, manager);
    }

    HANDLE retHandle;
    if (!::DuplicateHandle
    (
        ::GetCurrentProcess()
        , stdInOrg
        , ::GetCurrentProcess()
        , &retHandle
        , 0
        , FALSE
        , DUPLICATE_SAME_ACCESS))
    {
        ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotDupHandle, manager);
    }
    return retHandle;
}

void
WindowsFileMgr::close(FileHandle f, MemoryManager* const manager)
{
    if (!f)
		ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, manager);

    if (!::CloseHandle(f))
        ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotCloseFile, manager);
}

void
WindowsFileMgr::reset(FileHandle f, MemoryManager* const manager)
{
    if (!f)
		ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, manager);

    // Seek to the start of the file
    if (::SetFilePointer(f, 0, 0, FILE_BEGIN) == 0xFFFFFFFF)
        ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotResetFile, manager);
}

XMLFilePos
WindowsFileMgr::curPos(FileHandle f, MemoryManager* const manager)
{
    if (!f)
		ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, manager);

    // Get the current position
    const unsigned int curPos = ::SetFilePointer(f, 0, 0, FILE_CURRENT);
    if (curPos == 0xFFFFFFFF)
        ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotGetCurPos, manager);

    return curPos;
}

XMLFilePos
WindowsFileMgr::size(FileHandle f, MemoryManager* const manager)
{
    if (!f)
		ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, manager);

    DWORD high;
    DWORD low=GetFileSize(f, &high);
    if(low==INVALID_FILE_SIZE)
        // TODO: find a better exception
		ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotGetCurPos, manager);

    return low;
}

XMLSize_t
WindowsFileMgr::read(FileHandle f, XMLSize_t byteCount, XMLByte* buffer, MemoryManager* const manager)
{
    if (!f || !buffer)
		ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, manager);

    unsigned long bytesRead = 0;
    if (!::ReadFile(f, buffer, byteCount, &bytesRead, 0))
    {
        //
        //  Check specially for a broken pipe error. If we get this, it just
        //  means no more data from the pipe, so return zero.
        //
        if (::GetLastError() != ERROR_BROKEN_PIPE)
            ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotReadFromFile, manager);
    }
    return (unsigned int)bytesRead;
}

void
WindowsFileMgr::write(FileHandle f, XMLSize_t byteCount, const XMLByte* buffer, MemoryManager* const manager)
{
    if (!f || !buffer)
		ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, manager);

    const XMLByte* tmpFlush = buffer;

    while (true)
    {
        unsigned long  bytesWritten = 0;
        if (!::WriteFile(f, tmpFlush, byteCount, &bytesWritten, 0))
            ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotWriteToFile, manager);

        if (bytesWritten < byteCount) //incomplete write
        {
            tmpFlush+=bytesWritten;
            byteCount-=bytesWritten;
        }
        else
            return;
    }
}

XMLCh*
WindowsFileMgr::getFullPath(const XMLCh* const srcPath, MemoryManager* const manager)
{
    //
    //  If we are on NT, then use wide character APIs, else use ASCII APIs.
    //  We have to do it manually since we are only built in ASCII mode from
    //  the standpoint of the APIs.
    //
    if (_onNT)
    {
        // Use a local buffer that is big enough for the largest legal path
        const unsigned int bufSize = 1024;
        XMLCh tmpPath[bufSize + 1];

        XMLCh* namePart = 0;
        if (!::GetFullPathNameW((LPCWSTR)srcPath, bufSize, (LPWSTR)tmpPath, (LPWSTR*)&namePart))
            return 0;

        // Return a copy of the path
        return XMLString::replicate(tmpPath, manager);
    }
     else
    {
        // Transcode the incoming string
        char* tmpSrcPath = XMLString::transcode(srcPath, manager);
        ArrayJanitor<char> janSrcPath(tmpSrcPath, manager);

        // Use a local buffer that is big enough for the largest legal path
        const unsigned int bufSize = 511;
        char tmpPath[511 + 1];

        char* namePart = 0;
        if (!::GetFullPathNameA(tmpSrcPath, bufSize, tmpPath, &namePart))
            return 0;

        // Return a transcoded copy of the path
        return XMLString::transcode(tmpPath, manager);
    }
}

XMLCh*
WindowsFileMgr::getCurrentDirectory(MemoryManager* const manager)
{
    //
    //  If we are on NT, then use wide character APIs, else use ASCII APIs.
    //  We have to do it manually since we are only built in ASCII mode from
    //  the standpoint of the APIs.
    //
    if (_onNT)
    {
        // Use a local buffer that is big enough for the largest legal path
        const unsigned int bufSize = 1024;
        XMLCh tmpPath[bufSize + 1];

        if (!::GetCurrentDirectoryW(bufSize, (LPWSTR)tmpPath))
            return 0;

        // Return a copy of the path
        return XMLString::replicate(tmpPath, manager);
    }
     else
    {
        // Use a local buffer that is big enough for the largest legal path
        const unsigned int bufSize = 511;
        char tmpPath[511 + 1];

        if (!::GetCurrentDirectoryA(bufSize, tmpPath))
            return 0;

        // Return a transcoded copy of the path
        return XMLString::transcode(tmpPath, manager);
    }
}

bool
WindowsFileMgr::isRelative(const XMLCh* const toCheck, MemoryManager* const manager)
{
    // Check for pathological case of empty path
    if (!toCheck || !toCheck[0])
        return false;

    //
    //  If its starts with a drive, then it cannot be relative. Note that
    //  we checked the drive not being empty above, so worst case its one
    //  char long and the check of the 1st char will fail because its really
    //  a null character.
    //
    if (toCheck[1] == chColon)
    {
        if (((toCheck[0] >= chLatin_A) && (toCheck[0] <= chLatin_Z))
        ||  ((toCheck[0] >= chLatin_a) && (toCheck[0] <= chLatin_z)))
        {
            return false;
        }
    }

    //
    //  If it starts with a double slash, then it cannot be relative since
    //  it's a remote file.
    //
    if (isBackSlash(toCheck[0]) && isBackSlash(toCheck[1]))
        return false;

    // Else assume its a relative path
    return true;
}

XERCES_CPP_NAMESPACE_END

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

/*
 * $Id$
 */

#include <windows.h>

#include <xercesc/util/FileManagers/WindowsFileMgr.hpp>
#include <xercesc/util/Janitor.hpp>
#include <xercesc/util/XMLString.hpp>
#include <xercesc/util/XMLUniDefs.hpp>

XERCES_CPP_NAMESPACE_BEGIN

static bool isBackSlash(XMLCh c) {
    return c == chBackSlash ||
           c == chYenSign   ||
           c == chWonSign;
}

WindowsFileMgr::WindowsFileMgr()
{
    // Figure out if we are on NT and save that flag for later use
    OSVERSIONINFO   OSVer;
    OSVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
    ::GetVersionEx(&OSVer);
    _onNT = (OSVer.dwPlatformId == VER_PLATFORM_WIN32_NT);
}

WindowsFileMgr::~WindowsFileMgr()
{
}

FileHandle
WindowsFileMgr::open(const XMLCh* fileName, bool toWrite, MemoryManager* const manager)
{
    // Watch for obvious wierdness
    if (!fileName)
        return 0;

    //
    //  We have to play a little trick here. If its /x:.....
    //  style fully qualified path, we have to toss the leading /
    //  character.
    //
    const XMLCh* nameToOpen = fileName;
    if (*fileName == chForwardSlash)
    {
        if (XMLString::stringLen(fileName) > 3)
        {
            if (*(fileName + 2) == chColon)
            {
                const XMLCh chDrive = *(fileName + 1);
                if (((chDrive >= chLatin_A) && (chDrive <= chLatin_Z))
                ||  ((chDrive >= chLatin_a) && (chDrive <= chLatin_z)))
                {
                    nameToOpen = fileName + 1;
                }
            }

            // Similarly for UNC paths
            if ( *(fileName + 1) == *(fileName + 2) &&
                 (*(fileName + 1) == chForwardSlash ||
                  *(fileName + 1) == chBackSlash) )
            {
                nameToOpen = fileName + 1;
            }
        }
    }

    //  Ok, this might look stupid but its a semi-expedient way to deal
    //  with a thorny problem. Shift-JIS and some other Asian encodings
    //  are fundamentally broken and map both the backslash and the Yen
    //  sign to the same code point. Transcoders have to pick one or the
    //  other to map '\' to Unicode and tend to choose the Yen sign.
    //
    //  Unicode Yen or Won signs as directory separators will fail.
    //
    //  So, we will check this path name for Yen or won signs and, if they are
    //  there, we'll replace them with slashes.
    //
    //  A further twist:  we replace Yen and Won with forward slashes rather
    //   than back slashes.  Either form of slash will work as a directory
    //   separator.  On Win 95 and 98, though, Unicode back-slashes may
    //   fail to transode back to 8-bit 0x5C with some Unicode converters
    //   to  some of the problematic code pages.  Forward slashes always
    //   transcode correctly back to 8 bit char * form.
    //
    XMLCh *tmpUName = 0;

    const XMLCh* srcPtr = nameToOpen;
    while (*srcPtr)
    {
        if (*srcPtr == chYenSign ||
            *srcPtr == chWonSign)
            break;
        srcPtr++;
    }

    //
    //  If we found a yen, then we have to create a temp file name. Else
    //  go with the file name as is and save the overhead.
    //
    if (*srcPtr)
    {
        tmpUName = XMLString::replicate(nameToOpen, manager);

        XMLCh* tmpPtr = tmpUName;
        while (*tmpPtr)
        {
            if (*tmpPtr == chYenSign ||
                *tmpPtr == chWonSign)
                *tmpPtr = chForwardSlash;
            tmpPtr++;
        }
        nameToOpen = tmpUName;
    }
    FileHandle retVal = 0;
    if (_onNT)
    {
        retVal = ::CreateFileW
            (
            (LPCWSTR) nameToOpen
            , toWrite?GENERIC_WRITE:GENERIC_READ
            , FILE_SHARE_READ
            , 0
            , toWrite?CREATE_ALWAYS:OPEN_EXISTING
            , toWrite?FILE_ATTRIBUTE_NORMAL:FILE_FLAG_SEQUENTIAL_SCAN
            , 0
            );
    }
    else
    {
        //
        //  We are Win 95 / 98.  Take the Unicode file name back to (char *)
        //    so that we can open it.
        //
        char* tmpName = XMLString::transcode(nameToOpen, manager);
        retVal = ::CreateFileA
            (
            tmpName
            , toWrite?GENERIC_WRITE:GENERIC_READ
            , FILE_SHARE_READ
            , 0
            , toWrite?CREATE_ALWAYS:OPEN_EXISTING
            , toWrite?FILE_ATTRIBUTE_NORMAL:FILE_FLAG_SEQUENTIAL_SCAN
            , 0
            );
        manager->deallocate(tmpName);//delete [] tmpName;
    }

    if (tmpUName)
        manager->deallocate(tmpUName);//delete [] tmpUName;

    if (retVal == INVALID_HANDLE_VALUE)
        return 0;

    return retVal;
}

FileHandle
WindowsFileMgr::open(const char* path, bool toWrite, MemoryManager* const manager)
{
    FileHandle retVal = ::CreateFileA
    (
        path
        , toWrite?GENERIC_WRITE:GENERIC_READ
        , FILE_SHARE_READ
        , 0
        , toWrite?OPEN_ALWAYS:OPEN_EXISTING
        , toWrite?FILE_ATTRIBUTE_NORMAL:FILE_FLAG_SEQUENTIAL_SCAN
        , 0
    );

    if (retVal == INVALID_HANDLE_VALUE)
        return 0;

    return retVal;
}

FileHandle
WindowsFileMgr::openStdIn(MemoryManager* const manager)
{
    //
    //  Get the standard input handle. Duplicate it and return that copy
    //  since the outside world cannot tell the difference and will shut
    //  down this handle when its done with it. If we gave out the orignal,
    //  shutting it would prevent any further output.
    //
    HANDLE stdInOrg = ::GetStdHandle(STD_INPUT_HANDLE);
    if (stdInOrg == INVALID_HANDLE_VALUE) {
        XMLCh stdinStr[] = {chLatin_s, chLatin_t, chLatin_d, chLatin_i, chLatin_n, chNull};
        ThrowXMLwithMemMgr1(XMLPlatformUtilsException, XMLExcepts::File_CouldNotOpenFile, stdinStr, manager);
    }

    HANDLE retHandle;
    if (!::DuplicateHandle
    (
        ::GetCurrentProcess()
        , stdInOrg
        , ::GetCurrentProcess()
        , &retHandle
        , 0
        , FALSE
        , DUPLICATE_SAME_ACCESS))
    {
        ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotDupHandle, manager);
    }
    return retHandle;
}

void
WindowsFileMgr::close(FileHandle f, MemoryManager* const manager)
{
    if (!f)
		ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, manager);

    if (!::CloseHandle(f))
        ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotCloseFile, manager);
}

void
WindowsFileMgr::reset(FileHandle f, MemoryManager* const manager)
{
    if (!f)
		ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, manager);

    // Seek to the start of the file
    if (::SetFilePointer(f, 0, 0, FILE_BEGIN) == 0xFFFFFFFF)
        ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotResetFile, manager);
}

XMLFilePos
WindowsFileMgr::curPos(FileHandle f, MemoryManager* const manager)
{
    if (!f)
		ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, manager);

    // Get the current position
    const unsigned int curPos = ::SetFilePointer(f, 0, 0, FILE_CURRENT);
    if (curPos == 0xFFFFFFFF)
        ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotGetCurPos, manager);

    return curPos;
}

XMLFilePos
WindowsFileMgr::size(FileHandle f, MemoryManager* const manager)
{
    if (!f)
		ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, manager);

    DWORD high;
    DWORD low=GetFileSize(f, &high);
    if(low==INVALID_FILE_SIZE)
        // TODO: find a better exception
		ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotGetCurPos, manager);

    return low;
}

XMLSize_t
WindowsFileMgr::read(FileHandle f, XMLSize_t byteCount, XMLByte* buffer, MemoryManager* const manager)
{
    if (!f || !buffer)
		ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, manager);

    unsigned long bytesRead = 0;
    if (!::ReadFile(f, buffer, byteCount, &bytesRead, 0))
    {
        //
        //  Check specially for a broken pipe error. If we get this, it just
        //  means no more data from the pipe, so return zero.
        //
        if (::GetLastError() != ERROR_BROKEN_PIPE)
            ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotReadFromFile, manager);
    }
    return (unsigned int)bytesRead;
}

void
WindowsFileMgr::write(FileHandle f, XMLSize_t byteCount, const XMLByte* buffer, MemoryManager* const manager)
{
    if (!f || !buffer)
		ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, manager);

    const XMLByte* tmpFlush = buffer;

    while (true)
    {
        unsigned long  bytesWritten = 0;
        if (!::WriteFile(f, tmpFlush, byteCount, &bytesWritten, 0))
            ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotWriteToFile, manager);

        if (bytesWritten < byteCount) //incomplete write
        {
            tmpFlush+=bytesWritten;
            byteCount-=bytesWritten;
        }
        else
            return;
    }
}

XMLCh*
WindowsFileMgr::getFullPath(const XMLCh* const srcPath, MemoryManager* const manager)
{
    //
    //  If we are on NT, then use wide character APIs, else use ASCII APIs.
    //  We have to do it manually since we are only built in ASCII mode from
    //  the standpoint of the APIs.
    //
    if (_onNT)
    {
        // Use a local buffer that is big enough for the largest legal path
        const unsigned int bufSize = 1024;
        XMLCh tmpPath[bufSize + 1];

        XMLCh* namePart = 0;
        if (!::GetFullPathNameW((LPCWSTR)srcPath, bufSize, (LPWSTR)tmpPath, (LPWSTR*)&namePart))
            return 0;

        // Return a copy of the path
        return XMLString::replicate(tmpPath, manager);
    }
     else
    {
        // Transcode the incoming string
        char* tmpSrcPath = XMLString::transcode(srcPath, manager);
        ArrayJanitor<char> janSrcPath(tmpSrcPath, manager);

        // Use a local buffer that is big enough for the largest legal path
        const unsigned int bufSize = 511;
        char tmpPath[511 + 1];

        char* namePart = 0;
        if (!::GetFullPathNameA(tmpSrcPath, bufSize, tmpPath, &namePart))
            return 0;

        // Return a transcoded copy of the path
        return XMLString::transcode(tmpPath, manager);
    }
}

XMLCh*
WindowsFileMgr::getCurrentDirectory(MemoryManager* const manager)
{
    //
    //  If we are on NT, then use wide character APIs, else use ASCII APIs.
    //  We have to do it manually since we are only built in ASCII mode from
    //  the standpoint of the APIs.
    //
    if (_onNT)
    {
        // Use a local buffer that is big enough for the largest legal path
        const unsigned int bufSize = 1024;
        XMLCh tmpPath[bufSize + 1];

        if (!::GetCurrentDirectoryW(bufSize, (LPWSTR)tmpPath))
            return 0;

        // Return a copy of the path
        return XMLString::replicate(tmpPath, manager);
    }
     else
    {
        // Use a local buffer that is big enough for the largest legal path
        const unsigned int bufSize = 511;
        char tmpPath[511 + 1];

        if (!::GetCurrentDirectoryA(bufSize, tmpPath))
            return 0;

        // Return a transcoded copy of the path
        return XMLString::transcode(tmpPath, manager);
    }
}

bool
WindowsFileMgr::isRelative(const XMLCh* const toCheck, MemoryManager* const manager)
{
    // Check for pathological case of empty path
    if (!toCheck || !toCheck[0])
        return false;

    //
    //  If its starts with a drive, then it cannot be relative. Note that
    //  we checked the drive not being empty above, so worst case its one
    //  char long and the check of the 1st char will fail because its really
    //  a null character.
    //
    if (toCheck[1] == chColon)
    {
        if (((toCheck[0] >= chLatin_A) && (toCheck[0] <= chLatin_Z))
        ||  ((toCheck[0] >= chLatin_a) && (toCheck[0] <= chLatin_z)))
        {
            return false;
        }
    }

    //
    //  If it starts with a double slash, then it cannot be relative since
    //  it's a remote file.
    //
    if (isBackSlash(toCheck[0]))
        return false;

    // Else assume its a relative path
    return true;
}

XERCES_CPP_NAMESPACE_END

<|endoftext|>


<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
 * ITS 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Log$
 * Revision 1.12  2003/02/17 19:56:03  peiyongz
 * Re-prioritize search order for error message files.
 *
 * Revision 1.11  2002/12/12 16:53:25  peiyongz
 * Message file name changed.
 *
 * Revision 1.10  2002/12/06 16:29:17  peiyongz
 * $XERCESCROOT/msg created as home directory for message files, and
 * set default locale.
 *
 * Revision 1.9  2002/12/04 18:11:23  peiyongz
 * use $XERCESCROOT to search for icu resource bundle if XERCESC_NLS_HOME
 * undefined
 *
 * Revision 1.8  2002/11/20 20:28:17  peiyongz
 * fix to warning C4018: '>' : signed/unsigned mismatch
 *
 * Revision 1.7  2002/11/12 17:27:49  tng
 * DOM Message: add new domain for DOM Messages.
 *
 * Revision 1.6  2002/11/04 22:24:43  peiyongz
 * Locale setting for message loader
 *
 * Revision 1.5  2002/11/04 15:10:40  tng
 * C++ Namespace Support.
 *
 * Revision 1.4  2002/10/10 21:07:55  peiyongz
 * load resource files using environement vars and base name
 *
 * Revision 1.3  2002/10/02 17:08:50  peiyongz
 * XMLString::equals() to replace XMLString::compareString()
 *
 * Revision 1.2  2002/09/30 22:20:40  peiyongz
 * Build with ICU MsgLoader
 *
 * Revision 1.1.1.1  2002/02/01 22:22:19  peiyongz
 * sane_include
 *
 * Revision 1.7  2002/01/21 14:52:25  tng
 * [Bug 5847] ICUMsgLoader can't be compiled with gcc 3.0.3 and ICU2.  And also fix the memory leak introduced by Bug 2730 fix.
 *
 * Revision 1.6  2001/11/01 23:39:18  jasons
 * 2001-11-01  Jason E. Stewart  <jason@openinformatics.com>
 *
 * 	* src/util/MsgLoaders/ICU/ICUMsgLoader.hpp (Repository):
 * 	* src/util/MsgLoaders/ICU/ICUMsgLoader.cpp (Repository):
 * 	Updated to compile with ICU-1.8.1
 *
 * Revision 1.5  2000/03/02 19:55:14  roddey
 * This checkin includes many changes done while waiting for the
 * 1.1.0 code to be finished. I can't list them all here, but a list is
 * available elsewhere.
 *
 * Revision 1.4  2000/02/06 07:48:21  rahulj
 * Year 2K copyright swat.
 *
 * Revision 1.3  2000/01/19 00:58:38  roddey
 * Update to support new ICU 1.4 release.
 *
 * Revision 1.2  1999/11/19 21:24:03  aruna1
 * incorporated ICU 1.3.1 related changes int he file
 *
 * Revision 1.1.1.1  1999/11/09 01:07:23  twl
 * Initial checkin
 *
 * Revision 1.4  1999/11/08 20:45:26  rahul
 * Swat for adding in Product name and CVS comment log variable.
 *
 */

// ---------------------------------------------------------------------------
//  Includes
// ---------------------------------------------------------------------------
#include <xercesc/util/XercesDefs.hpp>
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/util/XMLMsgLoader.hpp>
#include <xercesc/util/XMLString.hpp>
#include <xercesc/util/XMLUniDefs.hpp>
#include <xercesc/util/Janitor.hpp>
#include "ICUMsgLoader.hpp"
#include "unicode/uloc.h"
#include "string.h"
#include <stdio.h>
#include <stdlib.h>

XERCES_CPP_NAMESPACE_BEGIN

// ---------------------------------------------------------------------------
//  Local static methods
// ---------------------------------------------------------------------------

// ---------------------------------------------------------------------------
//  Public Constructors and Destructor
// ---------------------------------------------------------------------------
ICUMsgLoader::ICUMsgLoader(const XMLCh* const  msgDomain)
:fLocaleBundle(0)
,fDomainBundle(0)
{
    /***
	    Validate msgDomain
    ***/
    if (!XMLString::equals(msgDomain, XMLUni::fgXMLErrDomain)    &&
        !XMLString::equals(msgDomain, XMLUni::fgExceptDomain)    &&
        !XMLString::equals(msgDomain, XMLUni::fgXMLDOMMsgDomain)    &&
        !XMLString::equals(msgDomain, XMLUni::fgValidityDomain)   )
    {
        XMLPlatformUtils::panic(XMLPlatformUtils::Panic_UnknownMsgDomain);
    }

    /***
	Resolve domainName
    ***/
    int     index = XMLString::lastIndexOf(msgDomain, chForwardSlash);
    char*   domainName = XMLString::transcode(&(msgDomain[index + 1]));
    ArrayJanitor<char> jan1(domainName);

    /***
        Location resolution priority

         1. XMLMsgLoader::getNLSHome(), set by user through
            XMLPlatformUtils::Initialize(), which provides user-specified
            location where the message loader shall retrieve error messages.

         2. envrionment var: XERCESC_NLS_HOME

         3. path $XERCESCROOT/msg
    ***/

    char locationBuf[1024];
    memset(locationBuf, 0, sizeof locationBuf);
    const char const *nlsHome = XMLMsgLoader::getNLSHome();

    if (nlsHome)
    {
    	strcpy(locationBuf, nlsHome);
        strcat(locationBuf, U_FILE_SEP_STRING);
    }
    else
    {
        nlsHome = getenv("XERCESC_NLS_HOME");
        if (nlsHome)
        {
            strcpy(locationBuf, nlsHome);
            strcat(locationBuf, U_FILE_SEP_STRING);
        }
        else
        {
            nlsHome = getenv("XERCESCROOT");
            if (nlsHome)
            {
                strcpy(locationBuf, nlsHome);
                strcat(locationBuf, U_FILE_SEP_STRING);
                strcat(locationBuf, "msg");
                strcat(locationBuf, U_FILE_SEP_STRING);
            }
            else
            {
                /***
                 leave it to ICU to decide where to search
                 for the error message.
                 ***/
            }
        }
    }

    /***
	Open the locale-specific resource bundle
    ***/
    strcat(locationBuf, "XercesMessages");
    UErrorCode err = U_ZERO_ERROR;
    uloc_setDefault("en_US", &err);   // in case user-specified locale unavailable
    err = U_ZERO_ERROR;
    fLocaleBundle = ures_open(locationBuf, XMLMsgLoader::getLocale(), &err);
    if (!U_SUCCESS(err) || fLocaleBundle == NULL)
    {
         XMLPlatformUtils::panic(XMLPlatformUtils::Panic_CantLoadMsgDomain);
    }

    /***
	Open the domain specific resource bundle within
	the locale-specific resource bundle
    ***/
    err = U_ZERO_ERROR;
    fDomainBundle = ures_getByKey(fLocaleBundle, domainName, NULL, &err);
    if (!U_SUCCESS(err) || fDomainBundle == NULL)
    {
        XMLPlatformUtils::panic(XMLPlatformUtils::Panic_CantLoadMsgDomain);
    }

}

ICUMsgLoader::~ICUMsgLoader()
{
    ures_close(fDomainBundle);
    ures_close(fLocaleBundle);
}

// ---------------------------------------------------------------------------
//  Implementation of the virtual message loader API
// ---------------------------------------------------------------------------
bool ICUMsgLoader::loadMsg( const   XMLMsgLoader::XMLMsgId  msgToLoad
                          ,         XMLCh* const            toFill
                          , const   unsigned int            maxChars)
{
    UErrorCode   err = U_ZERO_ERROR;
    int32_t      strLen = 0;

    // Assuming array format
    const UChar *name = ures_getStringByIndex(fDomainBundle, (int32_t)msgToLoad-1, &strLen, &err);

    if (!U_SUCCESS(err) || (name == NULL))
    {
        return false;
    }

    int retStrLen = strLen > (int32_t)maxChars ? maxChars : strLen;

    if (sizeof(UChar)==sizeof(XMLCh))
    {
        XMLString::moveChars(toFill, (XMLCh*)name, retStrLen);
        toFill[retStrLen] = (XMLCh) 0;
    }
    else
    {
        XMLCh* retStr = toFill;
        const UChar *srcPtr = name;

        while (retStrLen--)
           *retStr++ = *srcPtr++;

        *retStr = 0;
    }

    return true;
}

bool ICUMsgLoader::loadMsg( const   XMLMsgLoader::XMLMsgId  msgToLoad
                            ,       XMLCh* const            toFill
                            , const unsigned int           maxChars
                            , const XMLCh* const            repText1
                            , const XMLCh* const            repText2
                            , const XMLCh* const            repText3
                            , const XMLCh* const            repText4)
{
    // Call the other version to load up the message
    if (!loadMsg(msgToLoad, toFill, maxChars))
        return false;

    // And do the token replacement
    XMLString::replaceTokens(toFill, maxChars, repText1, repText2, repText3, repText4);
    return true;
}

bool ICUMsgLoader::loadMsg( const   XMLMsgLoader::XMLMsgId  msgToLoad
                            ,       XMLCh* const            toFill
                            , const unsigned int           maxChars
                            , const char* const             repText1
                            , const char* const             repText2
                            , const char* const             repText3
                            , const char* const             repText4)
{
    //
    //  Transcode the provided parameters and call the other version,
    //  which will do the replacement work.
    //
    XMLCh* tmp1 = 0;
    XMLCh* tmp2 = 0;
    XMLCh* tmp3 = 0;
    XMLCh* tmp4 = 0;

    bool bRet = false;
    if (repText1)
        tmp1 = XMLString::transcode(repText1);
    if (repText2)
        tmp2 = XMLString::transcode(repText2);
    if (repText3)
        tmp3 = XMLString::transcode(repText3);
    if (repText4)
        tmp4 = XMLString::transcode(repText4);

    bRet = loadMsg(msgToLoad, toFill, maxChars, tmp1, tmp2, tmp3, tmp4);

    if (tmp1)
        delete [] tmp1;
    if (tmp2)
        delete [] tmp2;
    if (tmp3)
        delete [] tmp3;
    if (tmp4)
        delete [] tmp4;

    return bRet;
}

XERCES_CPP_NAMESPACE_END
<commit_msg>Compilation error on Solaris.<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
 * ITS 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Log$
 * Revision 1.13  2003/02/19 15:37:57  peiyongz
 * Compilation error on Solaris.
 *
 * Revision 1.12  2003/02/17 19:56:03  peiyongz
 * Re-prioritize search order for error message files.
 *
 * Revision 1.11  2002/12/12 16:53:25  peiyongz
 * Message file name changed.
 *
 * Revision 1.10  2002/12/06 16:29:17  peiyongz
 * $XERCESCROOT/msg created as home directory for message files, and
 * set default locale.
 *
 * Revision 1.9  2002/12/04 18:11:23  peiyongz
 * use $XERCESCROOT to search for icu resource bundle if XERCESC_NLS_HOME
 * undefined
 *
 * Revision 1.8  2002/11/20 20:28:17  peiyongz
 * fix to warning C4018: '>' : signed/unsigned mismatch
 *
 * Revision 1.7  2002/11/12 17:27:49  tng
 * DOM Message: add new domain for DOM Messages.
 *
 * Revision 1.6  2002/11/04 22:24:43  peiyongz
 * Locale setting for message loader
 *
 * Revision 1.5  2002/11/04 15:10:40  tng
 * C++ Namespace Support.
 *
 * Revision 1.4  2002/10/10 21:07:55  peiyongz
 * load resource files using environement vars and base name
 *
 * Revision 1.3  2002/10/02 17:08:50  peiyongz
 * XMLString::equals() to replace XMLString::compareString()
 *
 * Revision 1.2  2002/09/30 22:20:40  peiyongz
 * Build with ICU MsgLoader
 *
 * Revision 1.1.1.1  2002/02/01 22:22:19  peiyongz
 * sane_include
 *
 * Revision 1.7  2002/01/21 14:52:25  tng
 * [Bug 5847] ICUMsgLoader can't be compiled with gcc 3.0.3 and ICU2.  And also fix the memory leak introduced by Bug 2730 fix.
 *
 * Revision 1.6  2001/11/01 23:39:18  jasons
 * 2001-11-01  Jason E. Stewart  <jason@openinformatics.com>
 *
 * 	* src/util/MsgLoaders/ICU/ICUMsgLoader.hpp (Repository):
 * 	* src/util/MsgLoaders/ICU/ICUMsgLoader.cpp (Repository):
 * 	Updated to compile with ICU-1.8.1
 *
 * Revision 1.5  2000/03/02 19:55:14  roddey
 * This checkin includes many changes done while waiting for the
 * 1.1.0 code to be finished. I can't list them all here, but a list is
 * available elsewhere.
 *
 * Revision 1.4  2000/02/06 07:48:21  rahulj
 * Year 2K copyright swat.
 *
 * Revision 1.3  2000/01/19 00:58:38  roddey
 * Update to support new ICU 1.4 release.
 *
 * Revision 1.2  1999/11/19 21:24:03  aruna1
 * incorporated ICU 1.3.1 related changes int he file
 *
 * Revision 1.1.1.1  1999/11/09 01:07:23  twl
 * Initial checkin
 *
 * Revision 1.4  1999/11/08 20:45:26  rahul
 * Swat for adding in Product name and CVS comment log variable.
 *
 */

// ---------------------------------------------------------------------------
//  Includes
// ---------------------------------------------------------------------------
#include <xercesc/util/XercesDefs.hpp>
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/util/XMLMsgLoader.hpp>
#include <xercesc/util/XMLString.hpp>
#include <xercesc/util/XMLUniDefs.hpp>
#include <xercesc/util/Janitor.hpp>
#include "ICUMsgLoader.hpp"
#include "unicode/uloc.h"
#include "string.h"
#include <stdio.h>
#include <stdlib.h>

XERCES_CPP_NAMESPACE_BEGIN

// ---------------------------------------------------------------------------
//  Local static methods
// ---------------------------------------------------------------------------

// ---------------------------------------------------------------------------
//  Public Constructors and Destructor
// ---------------------------------------------------------------------------
ICUMsgLoader::ICUMsgLoader(const XMLCh* const  msgDomain)
:fLocaleBundle(0)
,fDomainBundle(0)
{
    /***
	    Validate msgDomain
    ***/
    if (!XMLString::equals(msgDomain, XMLUni::fgXMLErrDomain)    &&
        !XMLString::equals(msgDomain, XMLUni::fgExceptDomain)    &&
        !XMLString::equals(msgDomain, XMLUni::fgXMLDOMMsgDomain)    &&
        !XMLString::equals(msgDomain, XMLUni::fgValidityDomain)   )
    {
        XMLPlatformUtils::panic(XMLPlatformUtils::Panic_UnknownMsgDomain);
    }

    /***
	Resolve domainName
    ***/
    int     index = XMLString::lastIndexOf(msgDomain, chForwardSlash);
    char*   domainName = XMLString::transcode(&(msgDomain[index + 1]));
    ArrayJanitor<char> jan1(domainName);

    /***
        Location resolution priority

         1. XMLMsgLoader::getNLSHome(), set by user through
            XMLPlatformUtils::Initialize(), which provides user-specified
            location where the message loader shall retrieve error messages.

         2. envrionment var: XERCESC_NLS_HOME

         3. path $XERCESCROOT/msg
    ***/

    char locationBuf[1024];
    memset(locationBuf, 0, sizeof locationBuf);
    const char *nlsHome = XMLMsgLoader::getNLSHome();

    if (nlsHome)
    {
    	strcpy(locationBuf, nlsHome);
        strcat(locationBuf, U_FILE_SEP_STRING);
    }
    else
    {
        nlsHome = getenv("XERCESC_NLS_HOME");
        if (nlsHome)
        {
            strcpy(locationBuf, nlsHome);
            strcat(locationBuf, U_FILE_SEP_STRING);
        }
        else
        {
            nlsHome = getenv("XERCESCROOT");
            if (nlsHome)
            {
                strcpy(locationBuf, nlsHome);
                strcat(locationBuf, U_FILE_SEP_STRING);
                strcat(locationBuf, "msg");
                strcat(locationBuf, U_FILE_SEP_STRING);
            }
            else
            {
                /***
                 leave it to ICU to decide where to search
                 for the error message.
                 ***/
            }
        }
    }

    /***
	Open the locale-specific resource bundle
    ***/
    strcat(locationBuf, "XercesMessages");
    UErrorCode err = U_ZERO_ERROR;
    uloc_setDefault("en_US", &err);   // in case user-specified locale unavailable
    err = U_ZERO_ERROR;
    fLocaleBundle = ures_open(locationBuf, XMLMsgLoader::getLocale(), &err);
    if (!U_SUCCESS(err) || fLocaleBundle == NULL)
    {
         XMLPlatformUtils::panic(XMLPlatformUtils::Panic_CantLoadMsgDomain);
    }

    /***
	Open the domain specific resource bundle within
	the locale-specific resource bundle
    ***/
    err = U_ZERO_ERROR;
    fDomainBundle = ures_getByKey(fLocaleBundle, domainName, NULL, &err);
    if (!U_SUCCESS(err) || fDomainBundle == NULL)
    {
        XMLPlatformUtils::panic(XMLPlatformUtils::Panic_CantLoadMsgDomain);
    }

}

ICUMsgLoader::~ICUMsgLoader()
{
    ures_close(fDomainBundle);
    ures_close(fLocaleBundle);
}

// ---------------------------------------------------------------------------
//  Implementation of the virtual message loader API
// ---------------------------------------------------------------------------
bool ICUMsgLoader::loadMsg( const   XMLMsgLoader::XMLMsgId  msgToLoad
                          ,         XMLCh* const            toFill
                          , const   unsigned int            maxChars)
{
    UErrorCode   err = U_ZERO_ERROR;
    int32_t      strLen = 0;

    // Assuming array format
    const UChar *name = ures_getStringByIndex(fDomainBundle, (int32_t)msgToLoad-1, &strLen, &err);

    if (!U_SUCCESS(err) || (name == NULL))
    {
        return false;
    }

    int retStrLen = strLen > (int32_t)maxChars ? maxChars : strLen;

    if (sizeof(UChar)==sizeof(XMLCh))
    {
        XMLString::moveChars(toFill, (XMLCh*)name, retStrLen);
        toFill[retStrLen] = (XMLCh) 0;
    }
    else
    {
        XMLCh* retStr = toFill;
        const UChar *srcPtr = name;

        while (retStrLen--)
           *retStr++ = *srcPtr++;

        *retStr = 0;
    }

    return true;
}

bool ICUMsgLoader::loadMsg( const   XMLMsgLoader::XMLMsgId  msgToLoad
                            ,       XMLCh* const            toFill
                            , const unsigned int           maxChars
                            , const XMLCh* const            repText1
                            , const XMLCh* const            repText2
                            , const XMLCh* const            repText3
                            , const XMLCh* const            repText4)
{
    // Call the other version to load up the message
    if (!loadMsg(msgToLoad, toFill, maxChars))
        return false;

    // And do the token replacement
    XMLString::replaceTokens(toFill, maxChars, repText1, repText2, repText3, repText4);
    return true;
}

bool ICUMsgLoader::loadMsg( const   XMLMsgLoader::XMLMsgId  msgToLoad
                            ,       XMLCh* const            toFill
                            , const unsigned int           maxChars
                            , const char* const             repText1
                            , const char* const             repText2
                            , const char* const             repText3
                            , const char* const             repText4)
{
    //
    //  Transcode the provided parameters and call the other version,
    //  which will do the replacement work.
    //
    XMLCh* tmp1 = 0;
    XMLCh* tmp2 = 0;
    XMLCh* tmp3 = 0;
    XMLCh* tmp4 = 0;

    bool bRet = false;
    if (repText1)
        tmp1 = XMLString::transcode(repText1);
    if (repText2)
        tmp2 = XMLString::transcode(repText2);
    if (repText3)
        tmp3 = XMLString::transcode(repText3);
    if (repText4)
        tmp4 = XMLString::transcode(repText4);

    bRet = loadMsg(msgToLoad, toFill, maxChars, tmp1, tmp2, tmp3, tmp4);

    if (tmp1)
        delete [] tmp1;
    if (tmp2)
        delete [] tmp2;
    if (tmp3)
        delete [] tmp3;
    if (tmp4)
        delete [] tmp4;

    return bRet;
}

XERCES_CPP_NAMESPACE_END
<|endoftext|>


<commit_before>#include <hash_db.h>

#include <QtCore/QDebug>
#include <QtCore/QFileInfo>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QVariant>

#include <QtSql/QSqlDatabase>
#include <QtSql/QSqlQuery>
#include <QtSql/QSqlError>
#include <QtSql/QSqlRecord>

QStringList schemas = (
	QStringList() <<
		QString("CREATE TABLE IF NOT EXISTS master_directory (hash TEXT NOT NULL PRIMARY KEY, path TEXT NOT NULL)") <<
		QString("CREATE TABLE IF NOT EXISTS checked_directory (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, hash TEXT NOT NULL, path TEXT NOT NULL)") <<
		QString("CREATE TABLE IF NOT EXISTS master_files (hash TEXT NOT NULL PRIMARY KEY, path TEXT NOT NULL)") <<
		QString("CREATE TABLE IF NOT EXISTS checked_files (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, hash TEXT NOT NULL, path TEXT NOT NULL)")
);

QStringList resetSchemas = (
	QStringList() <<
		QString("DROP TABLE IF EXISTS checked_files") <<
		QString("DROP TABLE IF EXISTS master_files") <<
		QString("DROP TABLE IF EXISTS checked_directory") <<
		QString("DROP TABLE IF EXISTS master_directory")
);

#define MAKE_QT_SQL_STATEMENT(name, the_db, the_statement)					\
	name = QSqlQuery(the_db); 												\
    if (!name.prepare(the_statement))										\
		{																	\
		qDebug() << "Failed to prepare " << the_statement;					\
		qDebug() << "Error: " << name.lastError();							\
		}

HashDb::HashDb(QObject* _parent) : QObject(_parent)
	{
	db = QSqlDatabase::addDatabase("QSQLITE");
	// db.setDatabaseName(":memory:");
	db.setDatabaseName("test_db.sqlite");
	db.open();
	init_database();
	MAKE_QT_SQL_STATEMENT(SQL_INSERT_DIRECTORY, db, "INSERT INTO master_directory (hash, path) VALUES(:hash, :path);");
	MAKE_QT_SQL_STATEMENT(SQL_HAS_DIRECTORY_BY_HASH, db, "SELECT hash, path FROM master_directory WHERE hash = :hash;");
	MAKE_QT_SQL_STATEMENT(SQL_CHECK_INSERT_DIRECTORY, db, "INSERT INTO checked_directory (hash, path) VALUES (:hash, :path);");

	MAKE_QT_SQL_STATEMENT(SQL_INSERT_FILE, db, "INSERT INTO master_files (hash, path) VALUES(:hash, :path);");
	MAKE_QT_SQL_STATEMENT(SQL_HAS_FILE_BY_HASH, db, "SELECT hash, path FROM master_files WHERE hash = :hash;");
	MAKE_QT_SQL_STATEMENT(SQL_CHECK_INSERT_FILE, db, "INSERT INTO checked_files (hash, path) VALUES(:hash, :path);");

	MAKE_QT_SQL_STATEMENT(SQL_NEW_DIRECTORIES, db, "SELECT hash, path FROM checked_directory WHERE hash NOT IN (SELECT hash FROM master_directory)");
	SQL_NEW_DIRECTORIES.setForwardOnly(true);

	MAKE_QT_SQL_STATEMENT(SQL_MISSING_DIRECTORIES, db, "SELECT hash, path FROM master_directory WHERE hash NOT IN (SELECT hash FROM checked_directory)");
	SQL_MISSING_DIRECTORIES.setForwardOnly(true);

	MAKE_QT_SQL_STATEMENT(SQL_NEW_FILES, db, "SELECT hash, path FROM checked_files WHERE hash NOT IN (SELECT hash FROM master_files)");
	SQL_NEW_FILES.setForwardOnly(true);

	MAKE_QT_SQL_STATEMENT(SQL_MISSING_FILES, db, "SELECT hash, path FROM master_files WHERE hash NOT IN (SELECT hash FROM checked_files)");
	SQL_MISSING_FILES.setForwardOnly(true);
	}

HashDb::~HashDb()
	{
	db.close();
	}

void HashDb::init_database()
	{
	if (db.isOpen())
		{
		for (QStringList::iterator iter = resetSchemas.begin();
			 iter != resetSchemas.end();
			 ++iter)
			 {
			 QSqlQuery setup(db);
			 setup.prepare((*iter));
			 if (!setup.exec())
			 	{
				Q_EMIT message("Failed to drop table...");
				Q_EMIT message(QString("Query: %1").arg(setup.executedQuery()));
				Q_EMIT message(QString("Error: %1").arg(setup.lastError().text()));

				qDebug() << "Failed to drop table...";
				qDebug() << "Query: " << setup.executedQuery();
				qDebug() << "Error: " << setup.lastError();
				}
	  		 setup.clear();
			 db.commit();
			 }
		for (QStringList::iterator iter = schemas.begin();
			 iter != schemas.end();
			 ++iter)
			 {
			 QSqlQuery setup(db);
			 setup.prepare((*iter));
			 if (!setup.exec())
			 	{
				Q_EMIT message("Failed to create table...");
				Q_EMIT message(QString("Query: %1").arg(setup.executedQuery()));
				Q_EMIT message(QString("Error: %1").arg(setup.lastError().text()));

				qDebug() << "Failed to create table...";
				qDebug() << "Query: " << setup.executedQuery();
				qDebug() << "Error: " << setup.lastError();
				}
			 setup.clear();
			 db.commit();
			 }
		 }
	}
void HashDb::resetDatabase()
	{
	Q_EMIT message("Resetting database...");
	init_database();
	}

void HashDb::addDirectory(QString _path, QByteArray _hash, bool _generate)
	{
	if (db.isOpen())
		{
		QSqlQuery insertion;
		if (_generate)
			{
			Q_EMIT message("Mode: Generate");
			insertion = SQL_INSERT_DIRECTORY;
			}
		else
			{
			Q_EMIT message("Mode: Validate");
			insertion = SQL_CHECK_INSERT_DIRECTORY;
			}
		insertion.bindValue(":hash", QVariant(_hash));
		insertion.bindValue(":path", _path);
		if (insertion.exec())
			{
			db.commit();
			}
		else
			{
			Q_EMIT message(QString("Failed to insert directory %1 with hash %2 into database").arg(_path).arg(QString(_hash)));
			Q_EMIT message(QString("Query: %1").arg(insertion.executedQuery()));
			QMapIterator<QString, QVariant> bv = insertion.boundValues();
			while(bv.hasNext())
				{
				bv.next();
				Q_EMIT message(QString("Mapped - Key: %1, Value: %2").arg(bv.key()).arg(bv.value().toString()));
				}
			Q_EMIT message(QString("Error: %1").arg(insertion.lastError().text()));
			}
		}
	}
void HashDb::addFile(QString _path, QByteArray _hash, bool _generate)
	{
	if (db.isOpen())
		{
		db.transaction();
		QSqlQuery insertion(db);
		if (_generate)
			{
			Q_EMIT message("Mode: Generate");
			insertion = SQL_INSERT_FILE;
			}
		else
			{
			Q_EMIT message("Mode: Validate");
			insertion = SQL_CHECK_INSERT_FILE;
			}
		insertion.bindValue(":hash", _hash);
		insertion.bindValue(":path", _path);
		if (insertion.exec())
			{
			db.commit();
			}
		else
			{
			Q_EMIT message(QString("Failed to insert file %1 with hash %2 into database").arg(_path).arg(QString(_hash)));
			Q_EMIT message(QString("Query: %1").arg(insertion.executedQuery()));
			QMapIterator<QString, QVariant> bv = insertion.boundValues();
			while(bv.hasNext())
				{
				bv.next();
				Q_EMIT message(QString("Mapped - Key: %1, Value: %2").arg(bv.key(), bv.value().toString()));
				}
			Q_EMIT message(QString("Error: %1").arg(insertion.lastError().text()));
			db.rollback();
			}
		}
	}
void HashDb::generateMissingObjects()
	{
	if (db.isOpen())
		{
		int col_path = 1;
		if (SQL_MISSING_FILES.exec())
			{
			while (SQL_MISSING_FILES.next())
				{
				QString path = SQL_MISSING_FILES.value(col_path).toString();
				Q_EMIT message_missing(path);
				}
			}
		else
			{
			Q_EMIT message(QString("Failed to retrieve missing records from the database"));
			Q_EMIT message(QString("Query: %1").arg(SQL_MISSING_FILES.executedQuery()));
			Q_EMIT message(QString("Error: %1").arg(SQL_MISSING_FILES.lastError().text()));
			}
		}
	}
void HashDb::generateNewObjects()
	{
	if (db.isOpen())
		{
		int col_path = 1;
		if (SQL_NEW_FILES.exec())
			{
			while (SQL_NEW_FILES.next())
				{
				QString path = SQL_NEW_FILES.value(col_path).toString();
				Q_EMIT message_new(path);
				}
			}
		else
			{
			Q_EMIT message(QString("Failed to retrieve new records from the database"));
			Q_EMIT message(QString("Query: %1").arg(SQL_NEW_FILES.executedQuery()));
			Q_EMIT message(QString("Error: %1").arg(SQL_NEW_FILES.lastError().text()));
			}
		}
	}
void HashDb::copyMissingObjects(QString _source_path, QString _destination_path)
	{
	if (db.isOpen())
		{
		int col_path = 1;
		if (SQL_MISSING_FILES.exec())
			{
			int count = 0;
			while (SQL_MISSING_FILES.next())
				{
				QString path = SQL_MISSING_FILES.value(col_path).toString();
				QString new_path = path;
				new_path.replace(_source_path, _destination_path);

				QFileInfo source_info(path);
				QFileInfo destination_info(new_path);

				/*
				qDebug() << "Processing Path:  " << path;
				qDebug() << "       File Name: " << source_info.fileName();
				qDebug() << "       File Path: " << source_info.absolutePath();
				qDebug() << "     Source Path: " << _source_path;

				qDebug() << "Generated Path:   " << new_path;
				qDebug() << "       File Name: " << destination_info.fileName();
				qDebug() << "       File Path: " << destination_info.absolutePath();
				qDebug() << "Destination Path: " << _destination_path;
				*/

				Q_EMIT copyFile(count, path, new_path);
				++count;
				}
			}
		else
			{
			Q_EMIT message(QString("Failed to retrieve missing records from the database"));
			Q_EMIT message(QString("Query: %1").arg(SQL_MISSING_FILES.executedQuery()));
			Q_EMIT message(QString("Error: %1").arg(SQL_MISSING_FILES.lastError().text()));
			}
		}
	}
<commit_msg>Restore<commit_after>#include <hash_db.h>

#include <QtCore/QDebug>
#include <QtCore/QFileInfo>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QVariant>

#include <QtSql/QSqlDatabase>
#include <QtSql/QSqlQuery>
#include <QtSql/QSqlError>
#include <QtSql/QSqlRecord>

QStringList schemas = (
	QStringList() <<
		QString("CREATE TABLE IF NOT EXISTS master_directory (hash TEXT NOT NULL PRIMARY KEY, path TEXT NOT NULL)") <<
		QString("CREATE TABLE IF NOT EXISTS checked_directory (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, hash TEXT NOT NULL, path TEXT NOT NULL)") <<
		QString("CREATE TABLE IF NOT EXISTS master_files (hash TEXT NOT NULL PRIMARY KEY, path TEXT NOT NULL)") <<
		QString("CREATE TABLE IF NOT EXISTS checked_files (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, hash TEXT NOT NULL, path TEXT NOT NULL)")
);

QStringList resetSchemas = (
	QStringList() <<
		QString("DROP TABLE IF EXISTS checked_files") <<
		QString("DROP TABLE IF EXISTS master_files") <<
		QString("DROP TABLE IF EXISTS checked_directory") <<
		QString("DROP TABLE IF EXISTS master_directory")
);

#define MAKE_QT_SQL_STATEMENT(name, the_db, the_statement)					\
	name = QSqlQuery(the_db); 												\
    if (!name.prepare(the_statement))										\
		{																	\
		qDebug() << "Failed to prepare " << the_statement;					\
		qDebug() << "Error: " << name.lastError();							\
		}

HashDb::HashDb(QObject* _parent) : QObject(_parent)
	{
	db = QSqlDatabase::addDatabase("QSQLITE");
	db.setDatabaseName(":memory:");
	db.open();
	init_database();
	MAKE_QT_SQL_STATEMENT(SQL_INSERT_DIRECTORY, db, "INSERT INTO master_directory (hash, path) VALUES(:hash, :path);");
	MAKE_QT_SQL_STATEMENT(SQL_HAS_DIRECTORY_BY_HASH, db, "SELECT hash, path FROM master_directory WHERE hash = :hash;");
	MAKE_QT_SQL_STATEMENT(SQL_CHECK_INSERT_DIRECTORY, db, "INSERT INTO checked_directory (hash, path) VALUES (:hash, :path);");

	MAKE_QT_SQL_STATEMENT(SQL_INSERT_FILE, db, "INSERT INTO master_files (hash, path) VALUES(:hash, :path);");
	MAKE_QT_SQL_STATEMENT(SQL_HAS_FILE_BY_HASH, db, "SELECT hash, path FROM master_files WHERE hash = :hash;");
	MAKE_QT_SQL_STATEMENT(SQL_CHECK_INSERT_FILE, db, "INSERT INTO checked_files (hash, path) VALUES(:hash, :path);");

	MAKE_QT_SQL_STATEMENT(SQL_NEW_DIRECTORIES, db, "SELECT hash, path FROM checked_directory WHERE hash NOT IN (SELECT hash FROM master_directory)");
	SQL_NEW_DIRECTORIES.setForwardOnly(true);

	MAKE_QT_SQL_STATEMENT(SQL_MISSING_DIRECTORIES, db, "SELECT hash, path FROM master_directory WHERE hash NOT IN (SELECT hash FROM checked_directory)");
	SQL_MISSING_DIRECTORIES.setForwardOnly(true);

	MAKE_QT_SQL_STATEMENT(SQL_NEW_FILES, db, "SELECT hash, path FROM checked_files WHERE hash NOT IN (SELECT hash FROM master_files)");
	SQL_NEW_FILES.setForwardOnly(true);

	MAKE_QT_SQL_STATEMENT(SQL_MISSING_FILES, db, "SELECT hash, path FROM master_files WHERE hash NOT IN (SELECT hash FROM checked_files)");
	SQL_MISSING_FILES.setForwardOnly(true);
	}

HashDb::~HashDb()
	{
	db.close();
	}

void HashDb::init_database()
	{
	if (db.isOpen())
		{
		for (QStringList::iterator iter = resetSchemas.begin();
			 iter != resetSchemas.end();
			 ++iter)
			 {
			 QSqlQuery setup(db);
			 setup.prepare((*iter));
			 if (!setup.exec())
			 	{
				Q_EMIT message("Failed to drop table...");
				Q_EMIT message(QString("Query: %1").arg(setup.executedQuery()));
				Q_EMIT message(QString("Error: %1").arg(setup.lastError().text()));

				/*
				qDebug() << "Failed to drop table...";
				qDebug() << "Query: " << setup.executedQuery();
				qDebug() << "Error: " << setup.lastError();
				*/
				}
	  		 setup.clear();
			 db.commit();
			 }
		for (QStringList::iterator iter = schemas.begin();
			 iter != schemas.end();
			 ++iter)
			 {
			 QSqlQuery setup(db);
			 setup.prepare((*iter));
			 if (!setup.exec())
			 	{
				Q_EMIT message("Failed to create table...");
				Q_EMIT message(QString("Query: %1").arg(setup.executedQuery()));
				Q_EMIT message(QString("Error: %1").arg(setup.lastError().text()));

				qDebug() << "Failed to create table...";
				qDebug() << "Query: " << setup.executedQuery();
				qDebug() << "Error: " << setup.lastError();
				}
			 setup.clear();
			 db.commit();
			 }
		 }
	}
void HashDb::resetDatabase()
	{
	Q_EMIT message("Resetting database...");
	init_database();
	}

void HashDb::addDirectory(QString _path, QByteArray _hash, bool _generate)
	{
	if (db.isOpen())
		{
		QSqlQuery insertion;
		if (_generate)
			{
			Q_EMIT message("Mode: Generate");
			insertion = SQL_INSERT_DIRECTORY;
			}
		else
			{
			Q_EMIT message("Mode: Validate");
			insertion = SQL_CHECK_INSERT_DIRECTORY;
			}
		insertion.bindValue(":hash", QVariant(_hash));
		insertion.bindValue(":path", _path);
		if (insertion.exec())
			{
			db.commit();
			}
		else
			{
			Q_EMIT message(QString("Failed to insert directory %1 with hash %2 into database").arg(_path).arg(QString(_hash)));
			Q_EMIT message(QString("Query: %1").arg(insertion.executedQuery()));
			QMapIterator<QString, QVariant> bv = insertion.boundValues();
			while(bv.hasNext())
				{
				bv.next();
				Q_EMIT message(QString("Mapped - Key: %1, Value: %2").arg(bv.key()).arg(bv.value().toString()));
				}
			Q_EMIT message(QString("Error: %1").arg(insertion.lastError().text()));
			}
		}
	}
void HashDb::addFile(QString _path, QByteArray _hash, bool _generate)
	{
	if (db.isOpen())
		{
		db.transaction();
		QSqlQuery insertion(db);
		if (_generate)
			{
			Q_EMIT message("Mode: Generate");
			insertion = SQL_INSERT_FILE;
			}
		else
			{
			Q_EMIT message("Mode: Validate");
			insertion = SQL_CHECK_INSERT_FILE;
			}
		insertion.bindValue(":hash", _hash);
		insertion.bindValue(":path", _path);
		if (insertion.exec())
			{
			db.commit();
			}
		else
			{
			Q_EMIT message(QString("Failed to insert file %1 with hash %2 into database").arg(_path).arg(QString(_hash)));
			Q_EMIT message(QString("Query: %1").arg(insertion.executedQuery()));
			QMapIterator<QString, QVariant> bv = insertion.boundValues();
			while(bv.hasNext())
				{
				bv.next();
				Q_EMIT message(QString("Mapped - Key: %1, Value: %2").arg(bv.key(), bv.value().toString()));
				}
			Q_EMIT message(QString("Error: %1").arg(insertion.lastError().text()));
			db.rollback();
			}
		}
	}
void HashDb::generateMissingObjects()
	{
	if (db.isOpen())
		{
		int col_path = 1;
		if (SQL_MISSING_FILES.exec())
			{
			while (SQL_MISSING_FILES.next())
				{
				QString path = SQL_MISSING_FILES.value(col_path).toString();
				Q_EMIT message_missing(path);
				}
			}
		else
			{
			Q_EMIT message(QString("Failed to retrieve missing records from the database"));
			Q_EMIT message(QString("Query: %1").arg(SQL_MISSING_FILES.executedQuery()));
			Q_EMIT message(QString("Error: %1").arg(SQL_MISSING_FILES.lastError().text()));
			}
		}
	}
void HashDb::generateNewObjects()
	{
	if (db.isOpen())
		{
		int col_path = 1;
		if (SQL_NEW_FILES.exec())
			{
			while (SQL_NEW_FILES.next())
				{
				QString path = SQL_NEW_FILES.value(col_path).toString();
				Q_EMIT message_new(path);
				}
			}
		else
			{
			Q_EMIT message(QString("Failed to retrieve new records from the database"));
			Q_EMIT message(QString("Query: %1").arg(SQL_NEW_FILES.executedQuery()));
			Q_EMIT message(QString("Error: %1").arg(SQL_NEW_FILES.lastError().text()));
			}
		}
	}
void HashDb::copyMissingObjects(QString _source_path, QString _destination_path)
	{
	if (db.isOpen())
		{
		int col_path = 1;
		if (SQL_MISSING_FILES.exec())
			{
			int count = 0;
			while (SQL_MISSING_FILES.next())
				{
				QString path = SQL_MISSING_FILES.value(col_path).toString();
				QString new_path = path;
				new_path.replace(_source_path, _destination_path);

				QFileInfo source_info(path);
				QFileInfo destination_info(new_path);

				/*
				qDebug() << "Processing Path:  " << path;
				qDebug() << "       File Name: " << source_info.fileName();
				qDebug() << "       File Path: " << source_info.absolutePath();
				qDebug() << "     Source Path: " << _source_path;

				qDebug() << "Generated Path:   " << new_path;
				qDebug() << "       File Name: " << destination_info.fileName();
				qDebug() << "       File Path: " << destination_info.absolutePath();
				qDebug() << "Destination Path: " << _destination_path;
				*/

				Q_EMIT copyFile(count, path, new_path);
				++count;
				}
			}
		else
			{
			Q_EMIT message(QString("Failed to retrieve missing records from the database"));
			Q_EMIT message(QString("Query: %1").arg(SQL_MISSING_FILES.executedQuery()));
			Q_EMIT message(QString("Error: %1").arg(SQL_MISSING_FILES.lastError().text()));
			}
		}
	}
<|endoftext|>


<commit_before>#include <string>

#include "SMT2Lib.h"

static const std::string parityDef =
  "(define-fun parity_flag ((x!1 (_ BitVec 8))) (_ BitVec 1)"
  "; x ^= x >> 4;"
  "; v &= 0xf;"
  "; return (0x6996 >> v) & 1;"
  "((_ extract 0 0)"
    "(bvlshr"
       "(_ bv27030 16)"
       "((_ zero_extend 8)"
        "(bvand"
          "(bvxor"
            "x!1"
            "(bvlshr x!1 (_ bv4 8)))"
          "(_ bv15 8)))))";

std::string smt2lib::init()
{
  return "(set-logic QF_AUFBV)" + parityDef;
}

/* Returns the 'bv' syntax based on a value and a size.
 * Mainly used for the SMT translation */
std::string smt2lib::bv(uint64_t value, uint64_t size)
{
  return "(_ bv" + std::to_string(value) + " " + std::to_string(size) + ")";
}

/* Returns the 'bv' syntax with sign extension applied to it. */
std::string smt2lib::sx(std::string expr, uint64_t size)
{
  return "((_ sign_extend " + std::to_string(size) + ") " + expr + ")";
}

/* Returns the 'bv' syntax with zero extension applied to it. */
std::string smt2lib::zx(std::string expr, uint64_t size)
{
  return "((_ zero_extend " + std::to_string(size) + ") " + expr + ")";;
}

/* Returns the 'bvadd' syntax. */
std::string smt2lib::bvadd(std::string op1, std::string op2)
{
  return "(bvadd " + op1 + " " + op2 + ")";
}

/* Returns the 'bvxor' syntax. */
std::string smt2lib::bvxor(std::string op1, std::string op2)
{
  return "(bvxor " + op1 + " " + op2 + ")";
}

/* Returns the 'bvand' syntax. */
std::string smt2lib::bvand(std::string op1, std::string op2)
{
  return "(bvand " + op1 + " " + op2 + ")";
}

/* Returns the 'bvnot' syntax. */
std::string smt2lib::bvnot(std::string op1)
{
  return "(bvnot " + op1 + ")";
}

/*
 * Returns the 'bvult' syntax.
 * bvult: unsigned less than
 */
std::string smt2lib::bvult(std::string op1, std::string op2)
{
  return "(bvult " + op1 + " " + op2 + ")";
}

/* Returns the 'extract' syntax based on a regSize.
 * Mainly used for the SMT translation */
std::string smt2lib::extract(uint64_t regSize)
{
  std::stringstream stream;

  switch(regSize){
    case 1:
      stream << "(_ extract 7 0)";
      break;
    case 2:
      stream << "(_ extract 15 0)";
      break;
    case 4:
      stream << "(_ extract 31 0)";
      break;
    case 8:
      stream << "(_ extract 63 0)";
      break;
  }

  return stream.str();
}

/* Returns the 'extract' syntax. */
std::string smt2lib::extract(uint64_t high, uint64_t low)
{
  return "(_ extract " + std::to_string(high) + " " + std::to_string(low) + ")";
}

/* Returns the 'extract' syntax. */
std::string smt2lib::extract(uint64_t high, uint64_t low, std::string expr)
{
  return "(" + smt2lib::extract(high, low) + " " + expr + ")";
}

/* Returns the 'declare' syntax is symbolic variable and a bit vector.
 * Mainly used for the SMT translation */
std::string smt2lib::declare(uint64_t idSymVar, uint64_t BitVecSize)
{
  std::stringstream stream;

  switch(BitVecSize){
    case 1:
      stream << "(declare-fun SymVar_" << idSymVar << " () (_ BitVec 8))";
      break;
    case 2:
      stream << "(declare-fun SymVar_" << idSymVar << " () (_ BitVec 16))";
      break;
    case 4:
      stream << "(declare-fun SymVar_" << idSymVar << " () (_ BitVec 32))";
      break;
    case 8:
      stream << "(declare-fun SymVar_" << idSymVar << " () (_ BitVec 64))";
      break;
  }

  return stream.str();
}

/* Returns the 'assert' syntax. */
std::string smt2lib::smtAssert(std::string expr)
{
  return "(assert " + expr + ")";
}

/* Returns the 'equal' syntax. */
std::string smt2lib::equal(std::string op1, std::string op2)
{
  return "(= " + op1 + " " + op2 + ")";
}

/* Returns a call to the parity function.
 * Returns the parity flag of one byte. If the number of bits set to 1 is even,
 * it returns (_ bv0 1) and (_ bv1 1) otherwise. */
std::string smt2lib::parityFlag(std::string expr)
{
  return "(parity_flag " + expr + ")";
}
<commit_msg>Fix a mistake ")" in the PF flag formulae<commit_after>#include <string>

#include "SMT2Lib.h"

static const std::string parityDef =
  "(define-fun parity_flag ((x!1 (_ BitVec 8))) (_ BitVec 1)"
  "; x ^= x >> 4;"
  "; v &= 0xf;"
  "; return (0x6996 >> v) & 1;"
  "((_ extract 0 0)"
    "(bvlshr"
       "(_ bv27030 16)"
       "((_ zero_extend 8)"
        "(bvand"
          "(bvxor"
            "x!1"
            "(bvlshr x!1 (_ bv4 8)))"
          "(_ bv15 8))))))";

std::string smt2lib::init()
{
  return "(set-logic QF_AUFBV)" + parityDef;
}

/* Returns the 'bv' syntax based on a value and a size.
 * Mainly used for the SMT translation */
std::string smt2lib::bv(uint64_t value, uint64_t size)
{
  return "(_ bv" + std::to_string(value) + " " + std::to_string(size) + ")";
}

/* Returns the 'bv' syntax with sign extension applied to it. */
std::string smt2lib::sx(std::string expr, uint64_t size)
{
  return "((_ sign_extend " + std::to_string(size) + ") " + expr + ")";
}

/* Returns the 'bv' syntax with zero extension applied to it. */
std::string smt2lib::zx(std::string expr, uint64_t size)
{
  return "((_ zero_extend " + std::to_string(size) + ") " + expr + ")";;
}

/* Returns the 'bvadd' syntax. */
std::string smt2lib::bvadd(std::string op1, std::string op2)
{
  return "(bvadd " + op1 + " " + op2 + ")";
}

/* Returns the 'bvxor' syntax. */
std::string smt2lib::bvxor(std::string op1, std::string op2)
{
  return "(bvxor " + op1 + " " + op2 + ")";
}

/* Returns the 'bvand' syntax. */
std::string smt2lib::bvand(std::string op1, std::string op2)
{
  return "(bvand " + op1 + " " + op2 + ")";
}

/* Returns the 'bvnot' syntax. */
std::string smt2lib::bvnot(std::string op1)
{
  return "(bvnot " + op1 + ")";
}

/*
 * Returns the 'bvult' syntax.
 * bvult: unsigned less than
 */
std::string smt2lib::bvult(std::string op1, std::string op2)
{
  return "(bvult " + op1 + " " + op2 + ")";
}

/* Returns the 'extract' syntax based on a regSize.
 * Mainly used for the SMT translation */
std::string smt2lib::extract(uint64_t regSize)
{
  std::stringstream stream;

  switch(regSize){
    case 1:
      stream << "(_ extract 7 0)";
      break;
    case 2:
      stream << "(_ extract 15 0)";
      break;
    case 4:
      stream << "(_ extract 31 0)";
      break;
    case 8:
      stream << "(_ extract 63 0)";
      break;
  }

  return stream.str();
}

/* Returns the 'extract' syntax. */
std::string smt2lib::extract(uint64_t high, uint64_t low)
{
  return "(_ extract " + std::to_string(high) + " " + std::to_string(low) + ")";
}

/* Returns the 'extract' syntax. */
std::string smt2lib::extract(uint64_t high, uint64_t low, std::string expr)
{
  return "(" + smt2lib::extract(high, low) + " " + expr + ")";
}

/* Returns the 'declare' syntax is symbolic variable and a bit vector.
 * Mainly used for the SMT translation */
std::string smt2lib::declare(uint64_t idSymVar, uint64_t BitVecSize)
{
  std::stringstream stream;

  switch(BitVecSize){
    case 1:
      stream << "(declare-fun SymVar_" << idSymVar << " () (_ BitVec 8))";
      break;
    case 2:
      stream << "(declare-fun SymVar_" << idSymVar << " () (_ BitVec 16))";
      break;
    case 4:
      stream << "(declare-fun SymVar_" << idSymVar << " () (_ BitVec 32))";
      break;
    case 8:
      stream << "(declare-fun SymVar_" << idSymVar << " () (_ BitVec 64))";
      break;
  }

  return stream.str();
}

/* Returns the 'assert' syntax. */
std::string smt2lib::smtAssert(std::string expr)
{
  return "(assert " + expr + ")";
}

/* Returns the 'equal' syntax. */
std::string smt2lib::equal(std::string op1, std::string op2)
{
  return "(= " + op1 + " " + op2 + ")";
}

/* Returns a call to the parity function.
 * Returns the parity flag of one byte. If the number of bits set to 1 is even,
 * it returns (_ bv0 1) and (_ bv1 1) otherwise. */
std::string smt2lib::parityFlag(std::string expr)
{
  return "(parity_flag " + expr + ")";
}
<|endoftext|>