<commit_before>/*
 * Copyright 2015 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkBmpCodec.h"
#include "SkCodecPriv.h"
#include "SkColorPriv.h"
#include "SkData.h"
#include "SkIcoCodec.h"
#include "SkPngCodec.h"
#include "SkStream.h"
#include "SkTDArray.h"
#include "SkTSort.h"

/*
 * Checks the start of the stream to see if the image is an Ico or Cur
 */
bool SkIcoCodec::IsIco(const void* buffer, size_t bytesRead) {
    const char icoSig[] = { '\x00', '\x00', '\x01', '\x00' };
    const char curSig[] = { '\x00', '\x00', '\x02', '\x00' };
    return bytesRead >= sizeof(icoSig) &&
            (!memcmp(buffer, icoSig, sizeof(icoSig)) ||
            !memcmp(buffer, curSig, sizeof(curSig)));
}

/*
 * Assumes IsIco was called and returned true
 * Creates an Ico decoder
 * Reads enough of the stream to determine the image format
 */
SkCodec* SkIcoCodec::NewFromStream(SkStream* stream) {
    // Ensure that we do not leak the input stream
    std::unique_ptr<SkStream> inputStream(stream);

    // Header size constants
    static const uint32_t kIcoDirectoryBytes = 6;
    static const uint32_t kIcoDirEntryBytes = 16;

    // Read the directory header
    std::unique_ptr<uint8_t[]> dirBuffer(new uint8_t[kIcoDirectoryBytes]);
    if (inputStream.get()->read(dirBuffer.get(), kIcoDirectoryBytes) !=
            kIcoDirectoryBytes) {
        SkCodecPrintf("Error: unable to read ico directory header.\n");
        return nullptr;
    }

    // Process the directory header
    const uint16_t numImages = get_short(dirBuffer.get(), 4);
    if (0 == numImages) {
        SkCodecPrintf("Error: No images embedded in ico.\n");
        return nullptr;
    }

    // Ensure that we can read all of indicated directory entries
    std::unique_ptr<uint8_t[]> entryBuffer(new uint8_t[numImages * kIcoDirEntryBytes]);
    if (inputStream.get()->read(entryBuffer.get(), numImages*kIcoDirEntryBytes) !=
            numImages*kIcoDirEntryBytes) {
        SkCodecPrintf("Error: unable to read ico directory entries.\n");
        return nullptr;
    }

    // This structure is used to represent the vital information about entries
    // in the directory header.  We will obtain this information for each
    // directory entry.
    struct Entry {
        uint32_t offset;
        uint32_t size;
    };
    std::unique_ptr<Entry[]> directoryEntries(new Entry[numImages]);

    // Iterate over directory entries
    for (uint32_t i = 0; i < numImages; i++) {
        // The directory entry contains information such as width, height,
        // bits per pixel, and number of colors in the color palette.  We will
        // ignore these fields since they are repeated in the header of the
        // embedded image.  In the event of an inconsistency, we would always
        // defer to the value in the embedded header anyway.

        // Specifies the size of the embedded image, including the header
        uint32_t size = get_int(entryBuffer.get(), 8 + i*kIcoDirEntryBytes);

        // Specifies the offset of the embedded image from the start of file.
        // It does not indicate the start of the pixel data, but rather the
        // start of the embedded image header.
        uint32_t offset = get_int(entryBuffer.get(), 12 + i*kIcoDirEntryBytes);

        // Save the vital fields
        directoryEntries.get()[i].offset = offset;
        directoryEntries.get()[i].size = size;
    }

    // It is "customary" that the embedded images will be stored in order of
    // increasing offset.  However, the specification does not indicate that
    // they must be stored in this order, so we will not trust that this is the
    // case.  Here we sort the embedded images by increasing offset.
    struct EntryLessThan {
        bool operator() (Entry a, Entry b) const {
            return a.offset < b.offset;
        }
    };
    EntryLessThan lessThan;
    SkTQSort(directoryEntries.get(), directoryEntries.get() + numImages - 1,
            lessThan);

    // Now will construct a candidate codec for each of the embedded images
    uint32_t bytesRead = kIcoDirectoryBytes + numImages * kIcoDirEntryBytes;
    std::unique_ptr<SkTArray<std::unique_ptr<SkCodec>, true>> codecs(
            new (SkTArray<std::unique_ptr<SkCodec>, true>)(numImages));
    for (uint32_t i = 0; i < numImages; i++) {
        uint32_t offset = directoryEntries.get()[i].offset;
        uint32_t size = directoryEntries.get()[i].size;

        // Ensure that the offset is valid
        if (offset < bytesRead) {
            SkCodecPrintf("Warning: invalid ico offset.\n");
            continue;
        }

        // If we cannot skip, assume we have reached the end of the stream and
        // stop trying to make codecs
        if (inputStream.get()->skip(offset - bytesRead) != offset - bytesRead) {
            SkCodecPrintf("Warning: could not skip to ico offset.\n");
            break;
        }
        bytesRead = offset;

        // Create a new stream for the embedded codec
        SkAutoFree buffer(sk_malloc_flags(size, 0));
        if (!buffer) {
            SkCodecPrintf("Warning: OOM trying to create embedded stream.\n");
            break;
        }

        if (inputStream->read(buffer.get(), size) != size) {
            SkCodecPrintf("Warning: could not create embedded stream.\n");
            break;
        }

        sk_sp<SkData> data(SkData::MakeFromMalloc(buffer.release(), size));
        std::unique_ptr<SkMemoryStream> embeddedStream(new SkMemoryStream(data));
        bytesRead += size;

        // Check if the embedded codec is bmp or png and create the codec
        SkCodec* codec = nullptr;
        if (SkPngCodec::IsPng((const char*) data->bytes(), data->size())) {
            codec = SkPngCodec::NewFromStream(embeddedStream.release());
        } else {
            codec = SkBmpCodec::NewFromIco(embeddedStream.release());
        }

        // Save a valid codec
        if (nullptr != codec) {
            codecs->push_back().reset(codec);
        }
    }

    // Recognize if there are no valid codecs
    if (0 == codecs->count()) {
        SkCodecPrintf("Error: could not find any valid embedded ico codecs.\n");
        return nullptr;
    }

    // Use the largest codec as a "suggestion" for image info
    size_t maxSize = 0;
    int maxIndex = 0;
    for (int i = 0; i < codecs->count(); i++) {
        SkImageInfo info = codecs->operator[](i)->getInfo();
        size_t size = info.getSafeSize(info.minRowBytes());

        if (size > maxSize) {
            maxSize = size;
            maxIndex = i;
        }
    }
    int width = codecs->operator[](maxIndex)->getInfo().width();
    int height = codecs->operator[](maxIndex)->getInfo().height();
    SkEncodedInfo info = codecs->operator[](maxIndex)->getEncodedInfo();
    SkColorSpace* colorSpace = codecs->operator[](maxIndex)->getInfo().colorSpace();

    // Note that stream is owned by the embedded codec, the ico does not need
    // direct access to the stream.
    return new SkIcoCodec(width, height, info, codecs.release(), sk_ref_sp(colorSpace));
}

/*
 * Creates an instance of the decoder
 * Called only by NewFromStream
 */
SkIcoCodec::SkIcoCodec(int width, int height, const SkEncodedInfo& info,
                       SkTArray<std::unique_ptr<SkCodec>, true>* codecs,
                       sk_sp<SkColorSpace> colorSpace)
    // The source SkColorSpaceXform::ColorFormat will not be used. The embedded
    // codec's will be used instead.
    : INHERITED(width, height, info, SkColorSpaceXform::ColorFormat(), nullptr,
                std::move(colorSpace))
    , fEmbeddedCodecs(codecs)
    , fCurrScanlineCodec(nullptr)
    , fCurrIncrementalCodec(nullptr)
{}

/*
 * Chooses the best dimensions given the desired scale
 */
SkISize SkIcoCodec::onGetScaledDimensions(float desiredScale) const {
    // We set the dimensions to the largest candidate image by default.
    // Regardless of the scale request, this is the largest image that we
    // will decode.
    int origWidth = this->getInfo().width();
    int origHeight = this->getInfo().height();
    float desiredSize = desiredScale * origWidth * origHeight;
    // At least one image will have smaller error than this initial value
    float minError = ((float) (origWidth * origHeight)) - desiredSize + 1.0f;
    int32_t minIndex = -1;
    for (int32_t i = 0; i < fEmbeddedCodecs->count(); i++) {
        int width = fEmbeddedCodecs->operator[](i)->getInfo().width();
        int height = fEmbeddedCodecs->operator[](i)->getInfo().height();
        float error = SkTAbs(((float) (width * height)) - desiredSize);
        if (error < minError) {
            minError = error;
            minIndex = i;
        }
    }
    SkASSERT(minIndex >= 0);

    return fEmbeddedCodecs->operator[](minIndex)->getInfo().dimensions();
}

int SkIcoCodec::chooseCodec(const SkISize& requestedSize, int startIndex) {
    SkASSERT(startIndex >= 0);

    // FIXME: Cache the index from onGetScaledDimensions?
    for (int i = startIndex; i < fEmbeddedCodecs->count(); i++) {
        if (fEmbeddedCodecs->operator[](i)->getInfo().dimensions() == requestedSize) {
            return i;
        }
    }

    return -1;
}

bool SkIcoCodec::onDimensionsSupported(const SkISize& dim) {
    return this->chooseCodec(dim, 0) >= 0;
}

/*
 * Initiates the Ico decode
 */
SkCodec::Result SkIcoCodec::onGetPixels(const SkImageInfo& dstInfo,
                                        void* dst, size_t dstRowBytes,
                                        const Options& opts, SkPMColor* colorTable,
                                        int* colorCount, int* rowsDecoded) {
    if (opts.fSubset) {
        // Subsets are not supported.
        return kUnimplemented;
    }

    int index = 0;
    SkCodec::Result result = kInvalidScale;
    while (true) {
        index = this->chooseCodec(dstInfo.dimensions(), index);
        if (index < 0) {
            break;
        }

        SkCodec* embeddedCodec = fEmbeddedCodecs->operator[](index).get();
        result = embeddedCodec->getPixels(dstInfo, dst, dstRowBytes, &opts, colorTable, colorCount);
        switch (result) {
            case kSuccess:
            case kIncompleteInput:
                // The embedded codec will handle filling incomplete images, so we will indicate
                // that all of the rows are initialized.
                *rowsDecoded = dstInfo.height();
                return result;
            default:
                // Continue trying to find a valid embedded codec on a failed decode.
                break;
        }

        index++;
    }

    SkCodecPrintf("Error: No matching candidate image in ico.\n");
    return result;
}

SkCodec::Result SkIcoCodec::onStartScanlineDecode(const SkImageInfo& dstInfo,
        const SkCodec::Options& options, SkPMColor colorTable[], int* colorCount) {
    int index = 0;
    SkCodec::Result result = kInvalidScale;
    while (true) {
        index = this->chooseCodec(dstInfo.dimensions(), index);
        if (index < 0) {
            break;
        }

        SkCodec* embeddedCodec = fEmbeddedCodecs->operator[](index).get();
        result = embeddedCodec->startScanlineDecode(dstInfo, &options, colorTable, colorCount);
        if (kSuccess == result) {
            fCurrScanlineCodec = embeddedCodec;
            fCurrIncrementalCodec = nullptr;
            return result;
        }

        index++;
    }

    SkCodecPrintf("Error: No matching candidate image in ico.\n");
    return result;
}

int SkIcoCodec::onGetScanlines(void* dst, int count, size_t rowBytes) {
    SkASSERT(fCurrScanlineCodec);
    return fCurrScanlineCodec->getScanlines(dst, count, rowBytes);
}

bool SkIcoCodec::onSkipScanlines(int count) {
    SkASSERT(fCurrScanlineCodec);
    return fCurrScanlineCodec->skipScanlines(count);
}

SkCodec::Result SkIcoCodec::onStartIncrementalDecode(const SkImageInfo& dstInfo,
        void* pixels, size_t rowBytes, const SkCodec::Options& options,
        SkPMColor* colorTable, int* colorCount) {
    int index = 0;
    while (true) {
        index = this->chooseCodec(dstInfo.dimensions(), index);
        if (index < 0) {
            break;
        }

        SkCodec* embeddedCodec = fEmbeddedCodecs->operator[](index).get();
        switch (embeddedCodec->startIncrementalDecode(dstInfo,
                pixels, rowBytes, &options, colorTable, colorCount)) {
            case kSuccess:
                fCurrIncrementalCodec = embeddedCodec;
                fCurrScanlineCodec = nullptr;
                return kSuccess;
            case kUnimplemented:
                // FIXME: embeddedCodec is a BMP. If scanline decoding would work,
                // return kUnimplemented so that SkSampledCodec will fall through
                // to use the scanline decoder.
                // Note that calling startScanlineDecode will require an extra
                // rewind. The embedded codec has an SkMemoryStream, which is
                // cheap to rewind, though it will do extra work re-reading the
                // header.
                // Also note that we pass nullptr for Options. This is because
                // Options that are valid for incremental decoding may not be
                // valid for scanline decoding.
                // Once BMP supports incremental decoding this workaround can go
                // away.
                if (embeddedCodec->startScanlineDecode(dstInfo, nullptr,
                        colorTable, colorCount) == kSuccess) {
                    return kUnimplemented;
                }
                // Move on to the next embedded codec.
                break;
            default:
                break;
        }

        index++;
    }

    SkCodecPrintf("Error: No matching candidate image in ico.\n");
    return kInvalidScale;
}

SkCodec::Result SkIcoCodec::onIncrementalDecode(int* rowsDecoded) {
    SkASSERT(fCurrIncrementalCodec);
    return fCurrIncrementalCodec->incrementalDecode(rowsDecoded);
}

SkCodec::SkScanlineOrder SkIcoCodec::onGetScanlineOrder() const {
    // FIXME: This function will possibly return the wrong value if it is called
    //        before startScanlineDecode()/startIncrementalDecode().
    if (fCurrScanlineCodec) {
        SkASSERT(!fCurrIncrementalCodec);
        return fCurrScanlineCodec->getScanlineOrder();
    }

    if (fCurrIncrementalCodec) {
        return fCurrIncrementalCodec->getScanlineOrder();
    }

    return INHERITED::onGetScanlineOrder();
}

SkSampler* SkIcoCodec::getSampler(bool createIfNecessary) {
    if (fCurrScanlineCodec) {
        SkASSERT(!fCurrIncrementalCodec);
        return fCurrScanlineCodec->getSampler(createIfNecessary);
    }

    if (fCurrIncrementalCodec) {
        return fCurrIncrementalCodec->getSampler(createIfNecessary);
    }

    return nullptr;
}
<commit_msg>ICO: Prevent calling 'new' with large values<commit_after>/*
 * Copyright 2015 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkBmpCodec.h"
#include "SkCodecPriv.h"
#include "SkColorPriv.h"
#include "SkData.h"
#include "SkIcoCodec.h"
#include "SkPngCodec.h"
#include "SkStream.h"
#include "SkTDArray.h"
#include "SkTSort.h"

/*
 * Checks the start of the stream to see if the image is an Ico or Cur
 */
bool SkIcoCodec::IsIco(const void* buffer, size_t bytesRead) {
    const char icoSig[] = { '\x00', '\x00', '\x01', '\x00' };
    const char curSig[] = { '\x00', '\x00', '\x02', '\x00' };
    return bytesRead >= sizeof(icoSig) &&
            (!memcmp(buffer, icoSig, sizeof(icoSig)) ||
            !memcmp(buffer, curSig, sizeof(curSig)));
}

/*
 * Assumes IsIco was called and returned true
 * Creates an Ico decoder
 * Reads enough of the stream to determine the image format
 */
SkCodec* SkIcoCodec::NewFromStream(SkStream* stream) {
    // Ensure that we do not leak the input stream
    std::unique_ptr<SkStream> inputStream(stream);

    // Header size constants
    static const uint32_t kIcoDirectoryBytes = 6;
    static const uint32_t kIcoDirEntryBytes = 16;

    // Read the directory header
    std::unique_ptr<uint8_t[]> dirBuffer(new uint8_t[kIcoDirectoryBytes]);
    if (inputStream.get()->read(dirBuffer.get(), kIcoDirectoryBytes) !=
            kIcoDirectoryBytes) {
        SkCodecPrintf("Error: unable to read ico directory header.\n");
        return nullptr;
    }

    // Process the directory header
    const uint16_t numImages = get_short(dirBuffer.get(), 4);
    if (0 == numImages) {
        SkCodecPrintf("Error: No images embedded in ico.\n");
        return nullptr;
    }

    // This structure is used to represent the vital information about entries
    // in the directory header.  We will obtain this information for each
    // directory entry.
    struct Entry {
        uint32_t offset;
        uint32_t size;
    };
    SkAutoFree dirEntryBuffer(sk_malloc_flags(sizeof(Entry) * numImages,
                                              SK_MALLOC_TEMP));
    if (!dirEntryBuffer) {
        SkCodecPrintf("Error: OOM allocating ICO directory for %i images.\n",
                      numImages);
        return nullptr;
    }
    auto* directoryEntries = reinterpret_cast<Entry*>(dirEntryBuffer.get());

    // Iterate over directory entries
    for (uint32_t i = 0; i < numImages; i++) {
        uint8_t entryBuffer[kIcoDirEntryBytes];
        if (inputStream->read(entryBuffer, kIcoDirEntryBytes) !=
                kIcoDirEntryBytes) {
            SkCodecPrintf("Error: Dir entries truncated in ico.\n");
            return nullptr;
        }

        // The directory entry contains information such as width, height,
        // bits per pixel, and number of colors in the color palette.  We will
        // ignore these fields since they are repeated in the header of the
        // embedded image.  In the event of an inconsistency, we would always
        // defer to the value in the embedded header anyway.

        // Specifies the size of the embedded image, including the header
        uint32_t size = get_int(entryBuffer, 8);

        // Specifies the offset of the embedded image from the start of file.
        // It does not indicate the start of the pixel data, but rather the
        // start of the embedded image header.
        uint32_t offset = get_int(entryBuffer, 12);

        // Save the vital fields
        directoryEntries[i].offset = offset;
        directoryEntries[i].size = size;
    }

    // It is "customary" that the embedded images will be stored in order of
    // increasing offset.  However, the specification does not indicate that
    // they must be stored in this order, so we will not trust that this is the
    // case.  Here we sort the embedded images by increasing offset.
    struct EntryLessThan {
        bool operator() (Entry a, Entry b) const {
            return a.offset < b.offset;
        }
    };
    EntryLessThan lessThan;
    SkTQSort(directoryEntries, &directoryEntries[numImages - 1], lessThan);

    // Now will construct a candidate codec for each of the embedded images
    uint32_t bytesRead = kIcoDirectoryBytes + numImages * kIcoDirEntryBytes;
    std::unique_ptr<SkTArray<std::unique_ptr<SkCodec>, true>> codecs(
            new (SkTArray<std::unique_ptr<SkCodec>, true>)(numImages));
    for (uint32_t i = 0; i < numImages; i++) {
        uint32_t offset = directoryEntries[i].offset;
        uint32_t size = directoryEntries[i].size;

        // Ensure that the offset is valid
        if (offset < bytesRead) {
            SkCodecPrintf("Warning: invalid ico offset.\n");
            continue;
        }

        // If we cannot skip, assume we have reached the end of the stream and
        // stop trying to make codecs
        if (inputStream.get()->skip(offset - bytesRead) != offset - bytesRead) {
            SkCodecPrintf("Warning: could not skip to ico offset.\n");
            break;
        }
        bytesRead = offset;

        // Create a new stream for the embedded codec
        SkAutoFree buffer(sk_malloc_flags(size, 0));
        if (!buffer) {
            SkCodecPrintf("Warning: OOM trying to create embedded stream.\n");
            break;
        }

        if (inputStream->read(buffer.get(), size) != size) {
            SkCodecPrintf("Warning: could not create embedded stream.\n");
            break;
        }

        sk_sp<SkData> data(SkData::MakeFromMalloc(buffer.release(), size));
        std::unique_ptr<SkMemoryStream> embeddedStream(new SkMemoryStream(data));
        bytesRead += size;

        // Check if the embedded codec is bmp or png and create the codec
        SkCodec* codec = nullptr;
        if (SkPngCodec::IsPng((const char*) data->bytes(), data->size())) {
            codec = SkPngCodec::NewFromStream(embeddedStream.release());
        } else {
            codec = SkBmpCodec::NewFromIco(embeddedStream.release());
        }

        // Save a valid codec
        if (nullptr != codec) {
            codecs->push_back().reset(codec);
        }
    }

    // Recognize if there are no valid codecs
    if (0 == codecs->count()) {
        SkCodecPrintf("Error: could not find any valid embedded ico codecs.\n");
        return nullptr;
    }

    // Use the largest codec as a "suggestion" for image info
    size_t maxSize = 0;
    int maxIndex = 0;
    for (int i = 0; i < codecs->count(); i++) {
        SkImageInfo info = codecs->operator[](i)->getInfo();
        size_t size = info.getSafeSize(info.minRowBytes());

        if (size > maxSize) {
            maxSize = size;
            maxIndex = i;
        }
    }
    int width = codecs->operator[](maxIndex)->getInfo().width();
    int height = codecs->operator[](maxIndex)->getInfo().height();
    SkEncodedInfo info = codecs->operator[](maxIndex)->getEncodedInfo();
    SkColorSpace* colorSpace = codecs->operator[](maxIndex)->getInfo().colorSpace();

    // Note that stream is owned by the embedded codec, the ico does not need
    // direct access to the stream.
    return new SkIcoCodec(width, height, info, codecs.release(), sk_ref_sp(colorSpace));
}

/*
 * Creates an instance of the decoder
 * Called only by NewFromStream
 */
SkIcoCodec::SkIcoCodec(int width, int height, const SkEncodedInfo& info,
                       SkTArray<std::unique_ptr<SkCodec>, true>* codecs,
                       sk_sp<SkColorSpace> colorSpace)
    // The source SkColorSpaceXform::ColorFormat will not be used. The embedded
    // codec's will be used instead.
    : INHERITED(width, height, info, SkColorSpaceXform::ColorFormat(), nullptr,
                std::move(colorSpace))
    , fEmbeddedCodecs(codecs)
    , fCurrScanlineCodec(nullptr)
    , fCurrIncrementalCodec(nullptr)
{}

/*
 * Chooses the best dimensions given the desired scale
 */
SkISize SkIcoCodec::onGetScaledDimensions(float desiredScale) const {
    // We set the dimensions to the largest candidate image by default.
    // Regardless of the scale request, this is the largest image that we
    // will decode.
    int origWidth = this->getInfo().width();
    int origHeight = this->getInfo().height();
    float desiredSize = desiredScale * origWidth * origHeight;
    // At least one image will have smaller error than this initial value
    float minError = ((float) (origWidth * origHeight)) - desiredSize + 1.0f;
    int32_t minIndex = -1;
    for (int32_t i = 0; i < fEmbeddedCodecs->count(); i++) {
        int width = fEmbeddedCodecs->operator[](i)->getInfo().width();
        int height = fEmbeddedCodecs->operator[](i)->getInfo().height();
        float error = SkTAbs(((float) (width * height)) - desiredSize);
        if (error < minError) {
            minError = error;
            minIndex = i;
        }
    }
    SkASSERT(minIndex >= 0);

    return fEmbeddedCodecs->operator[](minIndex)->getInfo().dimensions();
}

int SkIcoCodec::chooseCodec(const SkISize& requestedSize, int startIndex) {
    SkASSERT(startIndex >= 0);

    // FIXME: Cache the index from onGetScaledDimensions?
    for (int i = startIndex; i < fEmbeddedCodecs->count(); i++) {
        if (fEmbeddedCodecs->operator[](i)->getInfo().dimensions() == requestedSize) {
            return i;
        }
    }

    return -1;
}

bool SkIcoCodec::onDimensionsSupported(const SkISize& dim) {
    return this->chooseCodec(dim, 0) >= 0;
}

/*
 * Initiates the Ico decode
 */
SkCodec::Result SkIcoCodec::onGetPixels(const SkImageInfo& dstInfo,
                                        void* dst, size_t dstRowBytes,
                                        const Options& opts, SkPMColor* colorTable,
                                        int* colorCount, int* rowsDecoded) {
    if (opts.fSubset) {
        // Subsets are not supported.
        return kUnimplemented;
    }

    int index = 0;
    SkCodec::Result result = kInvalidScale;
    while (true) {
        index = this->chooseCodec(dstInfo.dimensions(), index);
        if (index < 0) {
            break;
        }

        SkCodec* embeddedCodec = fEmbeddedCodecs->operator[](index).get();
        result = embeddedCodec->getPixels(dstInfo, dst, dstRowBytes, &opts, colorTable, colorCount);
        switch (result) {
            case kSuccess:
            case kIncompleteInput:
                // The embedded codec will handle filling incomplete images, so we will indicate
                // that all of the rows are initialized.
                *rowsDecoded = dstInfo.height();
                return result;
            default:
                // Continue trying to find a valid embedded codec on a failed decode.
                break;
        }

        index++;
    }

    SkCodecPrintf("Error: No matching candidate image in ico.\n");
    return result;
}

SkCodec::Result SkIcoCodec::onStartScanlineDecode(const SkImageInfo& dstInfo,
        const SkCodec::Options& options, SkPMColor colorTable[], int* colorCount) {
    int index = 0;
    SkCodec::Result result = kInvalidScale;
    while (true) {
        index = this->chooseCodec(dstInfo.dimensions(), index);
        if (index < 0) {
            break;
        }

        SkCodec* embeddedCodec = fEmbeddedCodecs->operator[](index).get();
        result = embeddedCodec->startScanlineDecode(dstInfo, &options, colorTable, colorCount);
        if (kSuccess == result) {
            fCurrScanlineCodec = embeddedCodec;
            fCurrIncrementalCodec = nullptr;
            return result;
        }

        index++;
    }

    SkCodecPrintf("Error: No matching candidate image in ico.\n");
    return result;
}

int SkIcoCodec::onGetScanlines(void* dst, int count, size_t rowBytes) {
    SkASSERT(fCurrScanlineCodec);
    return fCurrScanlineCodec->getScanlines(dst, count, rowBytes);
}

bool SkIcoCodec::onSkipScanlines(int count) {
    SkASSERT(fCurrScanlineCodec);
    return fCurrScanlineCodec->skipScanlines(count);
}

SkCodec::Result SkIcoCodec::onStartIncrementalDecode(const SkImageInfo& dstInfo,
        void* pixels, size_t rowBytes, const SkCodec::Options& options,
        SkPMColor* colorTable, int* colorCount) {
    int index = 0;
    while (true) {
        index = this->chooseCodec(dstInfo.dimensions(), index);
        if (index < 0) {
            break;
        }

        SkCodec* embeddedCodec = fEmbeddedCodecs->operator[](index).get();
        switch (embeddedCodec->startIncrementalDecode(dstInfo,
                pixels, rowBytes, &options, colorTable, colorCount)) {
            case kSuccess:
                fCurrIncrementalCodec = embeddedCodec;
                fCurrScanlineCodec = nullptr;
                return kSuccess;
            case kUnimplemented:
                // FIXME: embeddedCodec is a BMP. If scanline decoding would work,
                // return kUnimplemented so that SkSampledCodec will fall through
                // to use the scanline decoder.
                // Note that calling startScanlineDecode will require an extra
                // rewind. The embedded codec has an SkMemoryStream, which is
                // cheap to rewind, though it will do extra work re-reading the
                // header.
                // Also note that we pass nullptr for Options. This is because
                // Options that are valid for incremental decoding may not be
                // valid for scanline decoding.
                // Once BMP supports incremental decoding this workaround can go
                // away.
                if (embeddedCodec->startScanlineDecode(dstInfo, nullptr,
                        colorTable, colorCount) == kSuccess) {
                    return kUnimplemented;
                }
                // Move on to the next embedded codec.
                break;
            default:
                break;
        }

        index++;
    }

    SkCodecPrintf("Error: No matching candidate image in ico.\n");
    return kInvalidScale;
}

SkCodec::Result SkIcoCodec::onIncrementalDecode(int* rowsDecoded) {
    SkASSERT(fCurrIncrementalCodec);
    return fCurrIncrementalCodec->incrementalDecode(rowsDecoded);
}

SkCodec::SkScanlineOrder SkIcoCodec::onGetScanlineOrder() const {
    // FIXME: This function will possibly return the wrong value if it is called
    //        before startScanlineDecode()/startIncrementalDecode().
    if (fCurrScanlineCodec) {
        SkASSERT(!fCurrIncrementalCodec);
        return fCurrScanlineCodec->getScanlineOrder();
    }

    if (fCurrIncrementalCodec) {
        return fCurrIncrementalCodec->getScanlineOrder();
    }

    return INHERITED::onGetScanlineOrder();
}

SkSampler* SkIcoCodec::getSampler(bool createIfNecessary) {
    if (fCurrScanlineCodec) {
        SkASSERT(!fCurrIncrementalCodec);
        return fCurrScanlineCodec->getSampler(createIfNecessary);
    }

    if (fCurrIncrementalCodec) {
        return fCurrIncrementalCodec->getSampler(createIfNecessary);
    }

    return nullptr;
}
<|endoftext|>


<commit_before>/*
 *
 *    Copyright (c) 2020 Project CHIP Authors
 *    Copyright (c) 2013-2017 Nest Labs, Inc.
 *    All rights reserved.
 *
 *    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.
 */

/**
 *    @file
 *      Implementation of CHIP Device Controller, a common class
 *      that implements discovery, pairing and provisioning of Weave
 *      devices.
 *
 */

#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
#endif
// module header, comes first
#include <controller/CHIPDeviceController.h>

#include <core/CHIPCore.h>
#include <core/CHIPEncoding.h>
#include <support/Base64.h>
#include <support/CodeUtils.h>
#include <support/ErrorStr.h>
#include <support/TimeUtils.h>
#include <support/logging/CHIPLogging.h>

#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <time.h>

namespace chip {
namespace DeviceController {

using namespace chip::Encoding;

ChipDeviceController::ChipDeviceController()
{
    mState      = kState_NotInitialized;
    AppState    = NULL;
    mConState   = kConnectionState_NotConnected;
    mDeviceCon  = NULL;
    mCurReqMsg  = NULL;
    mOnError    = NULL;
    mDeviceAddr = IPAddress::Any;
    mDevicePort = CHIP_PORT;
    mDeviceId   = 0;
    memset(&mOnComplete, 0, sizeof(mOnComplete));
}

CHIP_ERROR ChipDeviceController::Init()
{
    CHIP_ERROR err = CHIP_NO_ERROR;

    VerifyOrExit(mState == kState_NotInitialized, err = CHIP_ERROR_INCORRECT_STATE);

    mSystemLayer = new System::Layer();
    mInetLayer   = new Inet::InetLayer();

    // Initialize the CHIP System Layer.
    err = mSystemLayer->Init(NULL);
    if (err != CHIP_SYSTEM_NO_ERROR)
    {
        ChipLogError(Controller, "SystemLayer initialization failed: %s", ErrorStr(err));
    }
    SuccessOrExit(err);

    // Initialize the CHIP Inet layer.
    err = mInetLayer->Init(*mSystemLayer, NULL);
    if (err != INET_NO_ERROR)
    {
        ChipLogError(Controller, "InetLayer initialization failed: %s", ErrorStr(err));
    }
    SuccessOrExit(err);

    mState = kState_Initialized;

exit:
    return err;
}

CHIP_ERROR ChipDeviceController::Shutdown()
{
    if (mState != kState_Initialized)
    {
        return CHIP_ERROR_INCORRECT_STATE;
    }

    CHIP_ERROR err = CHIP_NO_ERROR;
    mState         = kState_NotInitialized;

    if (mDeviceCon != NULL)
    {
        mDeviceCon->Close();
        delete mDeviceCon;
        mDeviceCon = NULL;
    }
    mSystemLayer->Shutdown();
    mInetLayer->Shutdown();
    delete mSystemLayer;
    delete mInetLayer;
    mSystemLayer = NULL;
    mInetLayer   = NULL;

    mConState = kConnectionState_NotConnected;
    memset(&mOnComplete, 0, sizeof(mOnComplete));
    mOnError = NULL;

    return err;
}

CHIP_ERROR ChipDeviceController::ConnectDevice(uint64_t deviceId, IPAddress deviceAddr, void * appReqState,
                                               MessageReceiveHandler onMessageReceived, ErrorHandler onError, uint16_t devicePort)
{
    CHIP_ERROR err = CHIP_NO_ERROR;

    if (mState != kState_Initialized || mDeviceCon != NULL || mConState != kConnectionState_NotConnected)
    {
        return CHIP_ERROR_INCORRECT_STATE;
    }

    mDeviceId    = deviceId;
    mDeviceAddr  = deviceAddr;
    mDevicePort  = devicePort;
    mAppReqState = appReqState;
    mDeviceCon   = new UdpTransport();

    mDeviceCon->Init(mInetLayer);
    err = mDeviceCon->Connect(mDeviceId, mDeviceAddr, mDevicePort);
    SuccessOrExit(err);

    mDeviceCon->OnMessageReceived = OnReceiveMessage;
    mDeviceCon->OnReceiveError    = OnReceiveError;
    mDeviceCon->AppState          = this;

    mOnComplete.Response = onMessageReceived;
    mOnError             = onError;

    mConState = kConnectionState_Connected;

exit:
    if (err != CHIP_NO_ERROR && mDeviceCon != NULL)
    {
        mDeviceCon->Close();
        delete mDeviceCon;
        mDeviceCon = NULL;
    }
    return err;
}

CHIP_ERROR ChipDeviceController::GetDeviceAddress(IPAddress * deviceAddr, uint16_t * devicePort)
{
    CHIP_ERROR err = CHIP_NO_ERROR;

    if (mState != kState_Initialized || mConState != kConnectionState_Connected)
    {
        return CHIP_ERROR_INCORRECT_STATE;
    }

    if (deviceAddr)
    {
        *deviceAddr = mDeviceAddr;
    }
    if (devicePort)
    {
        *devicePort = mDevicePort;
    }

    return err;
}

bool ChipDeviceController::IsConnected()
{
    return kState_Initialized && mConState == kConnectionState_Connected;
}

CHIP_ERROR ChipDeviceController::DisconnectDevice()
{
    CHIP_ERROR err = CHIP_NO_ERROR;

    if (mState != kState_Initialized || mConState != kConnectionState_Connected)
    {
        return CHIP_ERROR_INCORRECT_STATE;
    }

    err = mDeviceCon->Close();
    delete mDeviceCon;
    mDeviceCon = NULL;
    mConState  = kConnectionState_NotConnected;
    return err;
};

CHIP_ERROR ChipDeviceController::SendMessage(void * appReqState, PacketBuffer * buffer)
{
    CHIP_ERROR err = CHIP_ERROR_INCORRECT_STATE;

    mAppReqState = appReqState;
    if (mConState == kConnectionState_Connected)
    {
        err = mDeviceCon->SendMessage(buffer);
    }

    return err;
}

CHIP_ERROR ChipDeviceController::GetLayers(Layer ** systemLayer, InetLayer ** inetLayer)
{
    if (mState != kState_Initialized)
    {
        return CHIP_ERROR_INCORRECT_STATE;
    }
    if (systemLayer != NULL)
    {
        *systemLayer = mSystemLayer;
    }
    if (inetLayer != NULL)
    {
        *inetLayer = mInetLayer;
    }

    return CHIP_NO_ERROR;
}

void ChipDeviceController::ServiceEvents()
{
#if CHIP_SYSTEM_CONFIG_USE_SOCKETS

    if (mState != kState_Initialized)
    {
        return;
    }
    // Set the select timeout to 100ms
    struct timeval aSleepTime;
    aSleepTime.tv_sec  = 0;
    aSleepTime.tv_usec = 100 * 1000;

    static bool printed = false;

    if (!printed)
    {
        {
            ChipLogProgress(Controller, "CHIP node ready to service events; PID: %d; PPID: %d\n", getpid(), getppid());
            printed = true;
        }
    }
    fd_set readFDs, writeFDs, exceptFDs;
    int numFDs = 0;

    FD_ZERO(&readFDs);
    FD_ZERO(&writeFDs);
    FD_ZERO(&exceptFDs);

    if (mSystemLayer->State() == System::kLayerState_Initialized)
        mSystemLayer->PrepareSelect(numFDs, &readFDs, &writeFDs, &exceptFDs, aSleepTime);

    if (mInetLayer->State == Inet::InetLayer::kState_Initialized)
        mInetLayer->PrepareSelect(numFDs, &readFDs, &writeFDs, &exceptFDs, aSleepTime);

    int selectRes = select(numFDs, &readFDs, &writeFDs, &exceptFDs, &aSleepTime);
    if (selectRes < 0)
    {
        ChipLogError(Controller, "select failed: %s\n", ErrorStr(System::MapErrorPOSIX(errno)));
        return;
    }

    if (mSystemLayer->State() == System::kLayerState_Initialized)
    {
        mSystemLayer->HandleSelectResult(selectRes, &readFDs, &writeFDs, &exceptFDs);
    }

    if (mInetLayer->State == Inet::InetLayer::kState_Initialized)
    {
        mInetLayer->HandleSelectResult(selectRes, &readFDs, &writeFDs, &exceptFDs);
    }
#endif
}

void ChipDeviceController::ClearRequestState()
{
    if (mCurReqMsg != NULL)
    {
        PacketBuffer::Free(mCurReqMsg);
        mCurReqMsg = NULL;
    }
}

void ChipDeviceController::OnReceiveMessage(UdpTransport * con, PacketBuffer * msgBuf, const IPPacketInfo * pktInfo)
{
    ChipDeviceController * mgr = (ChipDeviceController *) con->AppState;
    if (mgr->mConState == kConnectionState_Connected && mgr->mOnComplete.Response != NULL && pktInfo != NULL)
    {
        mgr->mOnComplete.Response(mgr, mgr->mAppReqState, msgBuf, pktInfo);
    }
}

void ChipDeviceController::OnReceiveError(UdpTransport * con, CHIP_ERROR err, const IPPacketInfo * pktInfo)
{
    ChipDeviceController * mgr = (ChipDeviceController *) con->AppState;
    if (mgr->mConState == kConnectionState_Connected && mgr->mOnError != NULL && pktInfo != NULL)
    {
        mgr->mOnError(mgr, mgr->mAppReqState, err, pktInfo);
    }
}

} // namespace DeviceController
} // namespace chip
<commit_msg>Removing another reference of peer node id in DeviceController this time<commit_after>/*
 *
 *    Copyright (c) 2020 Project CHIP Authors
 *    Copyright (c) 2013-2017 Nest Labs, Inc.
 *    All rights reserved.
 *
 *    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.
 */

/**
 *    @file
 *      Implementation of CHIP Device Controller, a common class
 *      that implements discovery, pairing and provisioning of Weave
 *      devices.
 *
 */

#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
#endif
// module header, comes first
#include <controller/CHIPDeviceController.h>

#include <core/CHIPCore.h>
#include <core/CHIPEncoding.h>
#include <support/Base64.h>
#include <support/CodeUtils.h>
#include <support/ErrorStr.h>
#include <support/TimeUtils.h>
#include <support/logging/CHIPLogging.h>

#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <time.h>

namespace chip {
namespace DeviceController {

using namespace chip::Encoding;

ChipDeviceController::ChipDeviceController()
{
    mState      = kState_NotInitialized;
    AppState    = NULL;
    mConState   = kConnectionState_NotConnected;
    mDeviceCon  = NULL;
    mCurReqMsg  = NULL;
    mOnError    = NULL;
    mDeviceAddr = IPAddress::Any;
    mDevicePort = CHIP_PORT;
    mDeviceId   = 0;
    memset(&mOnComplete, 0, sizeof(mOnComplete));
}

CHIP_ERROR ChipDeviceController::Init()
{
    CHIP_ERROR err = CHIP_NO_ERROR;

    VerifyOrExit(mState == kState_NotInitialized, err = CHIP_ERROR_INCORRECT_STATE);

    mSystemLayer = new System::Layer();
    mInetLayer   = new Inet::InetLayer();

    // Initialize the CHIP System Layer.
    err = mSystemLayer->Init(NULL);
    if (err != CHIP_SYSTEM_NO_ERROR)
    {
        ChipLogError(Controller, "SystemLayer initialization failed: %s", ErrorStr(err));
    }
    SuccessOrExit(err);

    // Initialize the CHIP Inet layer.
    err = mInetLayer->Init(*mSystemLayer, NULL);
    if (err != INET_NO_ERROR)
    {
        ChipLogError(Controller, "InetLayer initialization failed: %s", ErrorStr(err));
    }
    SuccessOrExit(err);

    mState = kState_Initialized;

exit:
    return err;
}

CHIP_ERROR ChipDeviceController::Shutdown()
{
    if (mState != kState_Initialized)
    {
        return CHIP_ERROR_INCORRECT_STATE;
    }

    CHIP_ERROR err = CHIP_NO_ERROR;
    mState         = kState_NotInitialized;

    if (mDeviceCon != NULL)
    {
        mDeviceCon->Close();
        delete mDeviceCon;
        mDeviceCon = NULL;
    }
    mSystemLayer->Shutdown();
    mInetLayer->Shutdown();
    delete mSystemLayer;
    delete mInetLayer;
    mSystemLayer = NULL;
    mInetLayer   = NULL;

    mConState = kConnectionState_NotConnected;
    memset(&mOnComplete, 0, sizeof(mOnComplete));
    mOnError = NULL;

    return err;
}

CHIP_ERROR ChipDeviceController::ConnectDevice(uint64_t deviceId, IPAddress deviceAddr, void * appReqState,
                                               MessageReceiveHandler onMessageReceived, ErrorHandler onError, uint16_t devicePort)
{
    CHIP_ERROR err = CHIP_NO_ERROR;

    if (mState != kState_Initialized || mDeviceCon != NULL || mConState != kConnectionState_NotConnected)
    {
        return CHIP_ERROR_INCORRECT_STATE;
    }

    mDeviceId    = deviceId;
    mDeviceAddr  = deviceAddr;
    mDevicePort  = devicePort;
    mAppReqState = appReqState;
    mDeviceCon   = new UdpTransport();

    mDeviceCon->Init(mInetLayer);
    err = mDeviceCon->Connect(mDeviceAddr, mDevicePort);
    SuccessOrExit(err);

    mDeviceCon->OnMessageReceived = OnReceiveMessage;
    mDeviceCon->OnReceiveError    = OnReceiveError;
    mDeviceCon->AppState          = this;

    mOnComplete.Response = onMessageReceived;
    mOnError             = onError;

    mConState = kConnectionState_Connected;

exit:
    if (err != CHIP_NO_ERROR && mDeviceCon != NULL)
    {
        mDeviceCon->Close();
        delete mDeviceCon;
        mDeviceCon = NULL;
    }
    return err;
}

CHIP_ERROR ChipDeviceController::GetDeviceAddress(IPAddress * deviceAddr, uint16_t * devicePort)
{
    CHIP_ERROR err = CHIP_NO_ERROR;

    if (mState != kState_Initialized || mConState != kConnectionState_Connected)
    {
        return CHIP_ERROR_INCORRECT_STATE;
    }

    if (deviceAddr)
    {
        *deviceAddr = mDeviceAddr;
    }
    if (devicePort)
    {
        *devicePort = mDevicePort;
    }

    return err;
}

bool ChipDeviceController::IsConnected()
{
    return kState_Initialized && mConState == kConnectionState_Connected;
}

CHIP_ERROR ChipDeviceController::DisconnectDevice()
{
    CHIP_ERROR err = CHIP_NO_ERROR;

    if (mState != kState_Initialized || mConState != kConnectionState_Connected)
    {
        return CHIP_ERROR_INCORRECT_STATE;
    }

    err = mDeviceCon->Close();
    delete mDeviceCon;
    mDeviceCon = NULL;
    mConState  = kConnectionState_NotConnected;
    return err;
};

CHIP_ERROR ChipDeviceController::SendMessage(void * appReqState, PacketBuffer * buffer)
{
    CHIP_ERROR err = CHIP_ERROR_INCORRECT_STATE;

    mAppReqState = appReqState;
    if (mConState == kConnectionState_Connected)
    {
        err = mDeviceCon->SendMessage(buffer);
    }

    return err;
}

CHIP_ERROR ChipDeviceController::GetLayers(Layer ** systemLayer, InetLayer ** inetLayer)
{
    if (mState != kState_Initialized)
    {
        return CHIP_ERROR_INCORRECT_STATE;
    }
    if (systemLayer != NULL)
    {
        *systemLayer = mSystemLayer;
    }
    if (inetLayer != NULL)
    {
        *inetLayer = mInetLayer;
    }

    return CHIP_NO_ERROR;
}

void ChipDeviceController::ServiceEvents()
{
#if CHIP_SYSTEM_CONFIG_USE_SOCKETS

    if (mState != kState_Initialized)
    {
        return;
    }
    // Set the select timeout to 100ms
    struct timeval aSleepTime;
    aSleepTime.tv_sec  = 0;
    aSleepTime.tv_usec = 100 * 1000;

    static bool printed = false;

    if (!printed)
    {
        {
            ChipLogProgress(Controller, "CHIP node ready to service events; PID: %d; PPID: %d\n", getpid(), getppid());
            printed = true;
        }
    }
    fd_set readFDs, writeFDs, exceptFDs;
    int numFDs = 0;

    FD_ZERO(&readFDs);
    FD_ZERO(&writeFDs);
    FD_ZERO(&exceptFDs);

    if (mSystemLayer->State() == System::kLayerState_Initialized)
        mSystemLayer->PrepareSelect(numFDs, &readFDs, &writeFDs, &exceptFDs, aSleepTime);

    if (mInetLayer->State == Inet::InetLayer::kState_Initialized)
        mInetLayer->PrepareSelect(numFDs, &readFDs, &writeFDs, &exceptFDs, aSleepTime);

    int selectRes = select(numFDs, &readFDs, &writeFDs, &exceptFDs, &aSleepTime);
    if (selectRes < 0)
    {
        ChipLogError(Controller, "select failed: %s\n", ErrorStr(System::MapErrorPOSIX(errno)));
        return;
    }

    if (mSystemLayer->State() == System::kLayerState_Initialized)
    {
        mSystemLayer->HandleSelectResult(selectRes, &readFDs, &writeFDs, &exceptFDs);
    }

    if (mInetLayer->State == Inet::InetLayer::kState_Initialized)
    {
        mInetLayer->HandleSelectResult(selectRes, &readFDs, &writeFDs, &exceptFDs);
    }
#endif
}

void ChipDeviceController::ClearRequestState()
{
    if (mCurReqMsg != NULL)
    {
        PacketBuffer::Free(mCurReqMsg);
        mCurReqMsg = NULL;
    }
}

void ChipDeviceController::OnReceiveMessage(UdpTransport * con, PacketBuffer * msgBuf, const IPPacketInfo * pktInfo)
{
    ChipDeviceController * mgr = (ChipDeviceController *) con->AppState;
    if (mgr->mConState == kConnectionState_Connected && mgr->mOnComplete.Response != NULL && pktInfo != NULL)
    {
        mgr->mOnComplete.Response(mgr, mgr->mAppReqState, msgBuf, pktInfo);
    }
}

void ChipDeviceController::OnReceiveError(UdpTransport * con, CHIP_ERROR err, const IPPacketInfo * pktInfo)
{
    ChipDeviceController * mgr = (ChipDeviceController *) con->AppState;
    if (mgr->mConState == kConnectionState_Connected && mgr->mOnError != NULL && pktInfo != NULL)
    {
        mgr->mOnError(mgr, mgr->mAppReqState, err, pktInfo);
    }
}

} // namespace DeviceController
} // namespace chip
<|endoftext|>


<commit_before>#include "rshell.h"
#include <stack>
using namespace std;
using namespace boost;

void testBrackets(string &s) {
	string tempTest = "test ";
	while(s.find('[') != string::npos) {
		int tmpPos = s.find('[');
		s.erase(tmpPos, 1);
		s.insert(tmpPos, tempTest);
		tmpPos = s.find(']');
		s.erase(tmpPos, 1);
	}
}

Rshell::Rshell() {
	//constructor will find the username and hostname
	userInput = "not written to yet*";
	username = getlogin();
	int temp = gethostname(hostname, 100);
	if(temp == -1) {
		cout << "error finding hostname ";
	}
}

void Rshell::prompt() {
	//simply prompts the user
	cout << username;
	cout << "@";
	cout << hostname;
	cout << "$ ";
}

void Rshell::terminal() {
	//terminal will prompt then parse the input
	while(1) {
		prompt();
		parse();
	}
}

void Rshell::parse() {
	//take in input
	getline(cin, userInput);

	//remove comments
	userInput = userInput.substr(0, userInput.find('#', 0));

	//Bracket handling to rewrite as test
	int openBrackets = 0;
	int closedBrackets = 0;
	int openParenthesis = 0;
	int closedParenthesis = 0;

	//for brackets, cannot be nested
	bool seenOpen = false;

	for(unsigned int i = 0; i < userInput.size(); i++) {
		char temp = userInput.at(i);
		if(temp == '[') {
			openBrackets++;
			if(seenOpen) {
				cout << "Error: Another Open Bracket b4 closed";
				cout << endl;
				return;
			}
			seenOpen = true;
		}
		else if(temp == ']') {
			closedBrackets++;
			seenOpen = false;
		}
		else if(temp == '(') {
			openParenthesis++;
		}
		else if (temp == ')') {
			closedParenthesis++;
		}
	}
	if(openBrackets != closedBrackets) {
		cout << "Error: Not enough brackets (unequal)" << endl;
		return;
	}

	if(openParenthesis != closedParenthesis) {
		cout << "Error: unequal amt of closed/open parenthesis\n";
		return;
	}
	testBrackets(userInput);

	//new code for parenthesis stack
	//
	//
	//
	//

	stack <string> parenStack;
	string temp = "";
	unsigned int j = 0;
	for(j=j; j < userInput.size(); j++)
	{
		char parenCheck = userInput.at(j);
		if(parenCheck == '(')
		{	while(userInput.at(j) != ')')
			{	j++;
				temp.push_back(userInput.at(j));
			}
			parenStack.push(temp);
		}
		else
		{
			//do normal commands without parenthesis
		}

	}

	//
	//
	//
	//

	//boost lib usages
	//we want to sepate the input into tokens
	char_separator<char> sep(" ");
	tokenizer< char_separator<char> > tokens(userInput, sep);

	BOOST_FOREACH(string t, tokens) {
		userTokens.push_back(t);
        }

	//with these tokens, we will separate the commands and composites
	//into their own string, in order to create the actual objects
	//str is used as a temp to store the commands as we get each arg
	//for it
	string str = "";
	for(unsigned int i = 0; i < userTokens.size(); i++) {
		//comp holds the single current token
		string comp = userTokens.at(i);

		//if the token is a composite, then we have reached the end of
		//our command, and we pull push the command string to a vector
		//and the specific type of composite to another vector
		if(comp != "||" && comp != "&&" && comp != ";") {
			str = str + " " + comp;
		}
		else {
			userCommands.push_back(str);
			if(comp == "||") {
				userComposites.push_back("||");
			}
			else if(comp == "&&") {
				userComposites.push_back(";");
			}
			else {
				userComposites.push_back("&&");
			}
			str = "";
		}
	}
	if(str != "") {
		userCommands.push_back(str);
		str = "";
	}
	//used to execute singular commands
	//simply makes a base* to a command object and executes it
	if(userComposites.empty()) {
		string s = userCommands.at(0);
		vector <string> temp;
		tokenizer< char_separator<char> > tempTokens(s, sep);
       		BOOST_FOREACH(string t, tempTokens) {
			temp.push_back(t);
	        }

		Base* element = new Command(temp);
		element->exec();
	}
	else {
		//create the array of command objects from the command strings
		vector <string> tempCommand;
		string s = "";
		for(unsigned int i = 0; i < userCommands.size(); i++) {
			s = userCommands.at(i);
			tokenizer< char_separator<char> > tempTokens(s, sep);
			BOOST_FOREACH(string t, tempTokens) {
                        	tempCommand.push_back(t);
			}
			Base* baseTemp = new Command(tempCommand);
			commands.push_back(baseTemp);
			tempCommand.clear();
                }

		//the first command always executes, and is used in composite
		//object creation
		bool firstRun = commands.at(0)->exec();

		//create our vector of composites
		for(unsigned int i = 0; i < userComposites.size(); i++) {
                        s = userComposites.at(i);
                        if(s == "&&") {
				Base* baseTemp = new AndComposite(firstRun,
				commands.at(i+1));
				composites.push_back(baseTemp);
			}
			else if(s == "||") {
				Base* baseTemp = new OrComposite(firstRun,
				commands.at(i+1));
				composites.push_back(baseTemp);
			}
			else {
				Base* baseTemp = new SemiColonComposite(firstRun,
				commands.at(i+1));
				composites.push_back(baseTemp);
			}
                        tempCommand.clear();
                }
		//now just execute our vector of composite objects
		for(unsigned int i = 0; i < composites.size(); i++) {
			composites.at(i)->exec();
		}
	}
	//lastly we clear our vectors for the next run
	userTokens.clear();
	userComposites.clear();
	userCommands.clear();
	commands.clear();
	composites.clear();
}
<commit_msg>parenthesis progress<commit_after>#include "rshell.h"
#include <stack>
using namespace std;
using namespace boost;

void testBrackets(string &s) {
	string tempTest = "test ";
	while(s.find('[') != string::npos) {
		int tmpPos = s.find('[');
		s.erase(tmpPos, 1);
		s.insert(tmpPos, tempTest);
		tmpPos = s.find(']');
		s.erase(tmpPos, 1);
	}
}

Rshell::Rshell() {
	//constructor will find the username and hostname
	userInput = "not written to yet*";
	username = getlogin();
	int temp = gethostname(hostname, 100);
	if(temp == -1) {
		cout << "error finding hostname ";
	}
}

void Rshell::prompt() {
	//simply prompts the user
	cout << username;
	cout << "@";
	cout << hostname;
	cout << "$ ";
}

void Rshell::terminal() {
	//terminal will prompt then parse the input
	while(1) {
		prompt();
		parse();
	}
}

void Rshell::parse() {
	//take in input
	getline(cin, userInput);

	//remove comments
	userInput = userInput.substr(0, userInput.find('#', 0));

	//Bracket handling to rewrite as test
	int openBrackets = 0;
	int closedBrackets = 0;
	int openParenthesis = 0;
	int closedParenthesis = 0;

	//for brackets, cannot be nested
	bool seenOpen = false;

	for(unsigned int i = 0; i < userInput.size(); i++) {
		char temp = userInput.at(i);
		if(temp == '[') {
			openBrackets++;
			if(seenOpen) {
				cout << "Error: Another Open Bracket b4 closed";
				cout << endl;
				return;
			}
			seenOpen = true;
		}
		else if(temp == ']') {
			closedBrackets++;
			seenOpen = false;
		}
		else if(temp == '(') {
			openParenthesis++;
		}
		else if (temp == ')') {
			closedParenthesis++;
		}
	}
	if(openBrackets != closedBrackets) {
		cout << "Error: Not enough brackets (unequal)" << endl;
		return;
	}

	if(openParenthesis != closedParenthesis) {
		cout << "Error: unequal amt of closed/open parenthesis\n";
		return;
	}
	testBrackets(userInput);

	//new code for parenthesis stack
	//
	//
	//
	//

	stack <string> parenStack;
	string temp = "";
	unsigned int j = 0;
	for(j=j; j < userInput.size(); j++)
	{
		char parenCheck = userInput.at(j);
		if(parenCheck == '(')
		{	while(userInput.at(j) != ')')
			{	j++;
				temp.push_back(userInput.at(j));
			}
			parenStack.push(temp);
			temp.clear();
		}
		else
		{
			//do normal commands without parenthesis
		}

	}

	//
	//
	//
	//

	//boost lib usages
	//we want to sepate the input into tokens
	char_separator<char> sep(" ");
	tokenizer< char_separator<char> > tokens(userInput, sep);

	BOOST_FOREACH(string t, tokens) {
		userTokens.push_back(t);
        }

	//with these tokens, we will separate the commands and composites
	//into their own string, in order to create the actual objects
	//str is used as a temp to store the commands as we get each arg
	//for it
	string str = "";
	for(unsigned int i = 0; i < userTokens.size(); i++) {
		//comp holds the single current token
		string comp = userTokens.at(i);

		//if the token is a composite, then we have reached the end of
		//our command, and we pull push the command string to a vector
		//and the specific type of composite to another vector
		if(comp != "||" && comp != "&&" && comp != ";") {
			str = str + " " + comp;
		}
		else {
			userCommands.push_back(str);
			if(comp == "||") {
				userComposites.push_back("||");
			}
			else if(comp == "&&") {
				userComposites.push_back(";");
			}
			else {
				userComposites.push_back("&&");
			}
			str = "";
		}
	}
	if(str != "") {
		userCommands.push_back(str);
		str = "";
	}
	//used to execute singular commands
	//simply makes a base* to a command object and executes it
	if(userComposites.empty()) {
		string s = userCommands.at(0);
		vector <string> temp;
		tokenizer< char_separator<char> > tempTokens(s, sep);
       		BOOST_FOREACH(string t, tempTokens) {
			temp.push_back(t);
	        }

		Base* element = new Command(temp);
		element->exec();
	}
	else {
		//create the array of command objects from the command strings
		vector <string> tempCommand;
		string s = "";
		for(unsigned int i = 0; i < userCommands.size(); i++) {
			s = userCommands.at(i);
			tokenizer< char_separator<char> > tempTokens(s, sep);
			BOOST_FOREACH(string t, tempTokens) {
                        	tempCommand.push_back(t);
			}
			Base* baseTemp = new Command(tempCommand);
			commands.push_back(baseTemp);
			tempCommand.clear();
                }

		//the first command always executes, and is used in composite
		//object creation
		bool firstRun = commands.at(0)->exec();

		//create our vector of composites
		for(unsigned int i = 0; i < userComposites.size(); i++) {
                        s = userComposites.at(i);
                        if(s == "&&") {
				Base* baseTemp = new AndComposite(firstRun,
				commands.at(i+1));
				composites.push_back(baseTemp);
			}
			else if(s == "||") {
				Base* baseTemp = new OrComposite(firstRun,
				commands.at(i+1));
				composites.push_back(baseTemp);
			}
			else {
				Base* baseTemp = new SemiColonComposite(firstRun,
				commands.at(i+1));
				composites.push_back(baseTemp);
			}
                        tempCommand.clear();
                }
		//now just execute our vector of composite objects
		for(unsigned int i = 0; i < composites.size(); i++) {
			composites.at(i)->exec();
		}
	}
	//lastly we clear our vectors for the next run
	userTokens.clear();
	userComposites.clear();
	userCommands.clear();
	commands.clear();
	composites.clear();
}
<|endoftext|>


<commit_before>/*
 * Copyright 2006-2008 The FLWOR 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.
 */
#include "zorba_debugger_runtime.h"

#include <memory>
#include <vector>
#include <sstream>
#include <fstream>

#include "store/api/store.h"

#include "api/zorbaimpl.h"
#include "api/xqueryimpl.h"
#include "api/serializerimpl.h"

#include "context/static_context.h"

#include "runtime/api/plan_wrapper.h"
#include "runtime/debug/zorba_debug_iterator.h"
#include "runtime/util/flowctl_exception.h"

#include "zorba/exception.h"
#include "zorba/printer_error_handler.h"
#include "zorbaerrors/errors.h"

#include "debugger/debugger_protocol.h"
#include "debugger/synchronous_logger.h"
#include "debugger/debugger_communication.h"
#include "debugger/zorba_debugger_commons.h"

#ifdef WIN32
#include <windows.h>
#define sleep(s) Sleep(s*1000)
#endif

namespace zorba {
  class EvalCommand : public Runnable
  {
  public:
    EvalCommand(ZorbaDebuggerCommons* aCommons,
      DebuggerCommunicator* aCommunicator,
      const xqpString& aEvalString,
      Zorba_SerializerOptions& aSerOpts,
      Id aId)
      :
    theCommons(aCommons),
    theCommunicator(aCommunicator),
    theEvalString(aEvalString),
    theSerOpts(aSerOpts),
    theId(aId)
    {}

    virtual ~EvalCommand() {}

    /**
    * @brief runs the evaluation command in the current scope.
    *
    * Runs theEvalString in. This method is supposed to run in its own thread
    * and it will send an evaluation event back to the client after finishing.
    *
    * @pre theCommons != NULL
    * @pre theCommunicator != NULL
    */
    virtual void run()
    {
      // Check preconditions
      ZORBA_ASSERT(theCommons != NULL);
      ZORBA_ASSERT(theCommunicator != NULL);
      std::auto_ptr<EvaluatedEvent> lEvent;

      try {
        lEvent.reset(
          new EvaluatedEvent(
            theId,
            theEvalString,
            theCommons->eval(theEvalString, theSerOpts)));
      } catch (error::ZorbaError& lError) {
        lEvent.reset(
          new EvaluatedEvent(
            theId,
            theEvalString,
            lError.toString()));
      }
      theCommunicator->sendEvent(lEvent.get());
    }

    virtual void finish()
    {
    }

  private:
    ZorbaDebuggerCommons*     theCommons;
    DebuggerCommunicator*     theCommunicator;
    xqpString                 theEvalString;
    Zorba_SerializerOptions&  theSerOpts;
    Id                        theId;
  };

ZorbaDebuggerRuntime::ZorbaDebuggerRuntime(
  XQueryImpl* xqueryImpl,
  std::ostream& oStream,
  Zorba_SerializerOptions& serializerOptions,
  DebuggerCommunicator* communicator,
  itemHandler aHandler,
  void* aCallBackData)
  : theQuery(xqueryImpl),
    theOStream(oStream),
    theSerializerOptions(serializerOptions),
    theCommunicator(communicator),
    theWrapper(theQuery->generateWrapper()),
    theExecStatus(QUERY_IDLE),
    theCurrentMessage(0),
    theNotSendTerminateEvent(false),
    thePlanIsOpen(false),
    theSerializer(0),
    theItemHandler(aHandler),
    theCallbackData(aCallBackData)
{
}

ZorbaDebuggerRuntime::~ZorbaDebuggerRuntime()
{
  delete theSerializer;
}

// this is the main loop of the thread
// the runtime thread terminates if this method finishes
void
ZorbaDebuggerRuntime::run()
{
  theWrapper->open();
  thePlanIsOpen = true;

  std::auto_ptr<StartedEvent> lStarted(new StartedEvent());
  theCommunicator->sendEvent(lStarted.get());
  lStarted.reset(0);

  runQuery();
}

void ZorbaDebuggerRuntime::finish()
{
  if (thePlanIsOpen) {
    theWrapper->close();
  }
  if (!theNotSendTerminateEvent) {
    TerminatedEvent lEvent;
    theCommunicator->sendEvent(&lEvent);
  }
}

void ZorbaDebuggerRuntime::resetRuntime()
{
  theWrapper = theQuery->generateWrapper();
  thePlanIsOpen = false;
  theExecStatus = QUERY_IDLE;
  theNotSendTerminateEvent = false;
  reset();
}

bool ZorbaDebuggerRuntime::processMessage(AbstractCommandMessage* message)
{
  AutoLock lLock(theLock, Lock::WRITE);
  theCurrentMessage = message;

  switch (theCurrentMessage->getCommandSet())
  {
  case EXECUTION:
    if (execCommands()) {
      return true;
    }
    break;
  case BREAKPOINTS:
    breakpointCommands();
    break;
  case STATIC:
    staticCommands();
    break;
  case DYNAMIC:
    dynamicCommands();
    break;
  default:
    throw InvalidCommandException("Internal Error: Command set not implemented");
  }
  return false;
}

ExecutionStatus ZorbaDebuggerRuntime::getExecutionStatus() const
{
  AutoLock lLock(theLock, Lock::READ);
  return theExecStatus;
}

void ZorbaDebuggerRuntime::runQuery()
{
  theLock.wlock();
  theExecStatus = theExecStatus == QUERY_SUSPENDED ? QUERY_RESUMED : QUERY_RUNNING;

  // used to print error messages
  PrinterErrorHandler lErrorHandler(theOStream);

  try {
    theWrapper->thePlanState->theDebuggerCommons->setRuntime(this);
    theLock.unlock();

    delete theSerializer;
    theSerializer = new serializer(theQuery->theErrorManager);
    SerializerImpl::setSerializationParameters(
      *theSerializer, theSerializerOptions);
    if (theItemHandler) {
      theSerializer->serialize((intern::Serializable*)theWrapper, theOStream,
        theItemHandler, theCallbackData);
    } else {
      theSerializer->serialize((intern::Serializable*)theWrapper, theOStream);
    }

    theOStream.flush();
  } catch (FlowCtlException&) {
    // Runtime correctly terminated by user interrupt
  } catch (error::ZorbaError& e){
    // this does not rethrow but only print the error message
    ZorbaImpl::notifyError(&lErrorHandler, e);
  }
  theLock.wlock();
  theExecStatus = QUERY_TERMINATED;
  theLock.unlock();
}

bool
ZorbaDebuggerRuntime::execCommands()
{
  switch (theCurrentMessage->getCommand())
  {
  case RESUME:
    resumeQuery();
    break;
  case TERMINATE:
    terminateRuntime();
    return true;
  case STEP:
    step();
    break;
  default:
    assert(false);
  }
  return false;
}

void ZorbaDebuggerRuntime::breakpointCommands()
{
  switch (theCurrentMessage->getCommand())
  {
  case SET:
    {
      SetMessage* lMessage;
#ifndef NDEBUG
      lMessage = dynamic_cast<SetMessage*>(theCurrentMessage);
      assert(lMessage);
#else
      lMessage = static_cast<SetMessage*>(theCurrentMessage);
#endif
      std::auto_ptr<SetReply> lReply(new SetReply(theCurrentMessage->getId(), DEBUGGER_NO_ERROR));
      std::map<unsigned int, QueryLoc> lLocations = lMessage->getLocations();
      std::map<unsigned int, QueryLoc>::iterator lIter;
      for (lIter = lLocations.begin(); lIter != lLocations.end(); lIter++) {
        QueryLoc lLoc = addBreakpoint(lIter->second, lIter->first);
        lReply->addBreakpoint(lIter->first, lLoc);
      }
      theCurrentMessage->setReplyMessage(lReply.release());
    }
    break;
  case CLEAR:
    {
      ZORBA_ASSERT(dynamic_cast<ClearMessage*>(theCurrentMessage));
      ClearMessage* lMessage = static_cast<ClearMessage*>(theCurrentMessage);
      std::vector<unsigned int> lIds = lMessage->getIds();
      std::vector<unsigned int>::iterator lIter;
      for (lIter = lIds.begin(); lIter != lIds.end(); ++lIter) {
        ZorbaDebuggerCommons* lCommons =
          theWrapper->thePlanState->theDebuggerCommons;
        lCommons->clearBreakpoint(*lIter);
      }
    }
    break;
  }
}

void ZorbaDebuggerRuntime::staticCommands()
{
  switch (theCurrentMessage->getCommand())
  {
  case LIST:
    theCurrentMessage->setReplyMessage(listSource());
    break;
  }
}

void ZorbaDebuggerRuntime::dynamicCommands()
{
  if (theExecStatus != QUERY_SUSPENDED) {
    std::auto_ptr<ReplyMessage> lReply(
      new ReplyMessage(theCurrentMessage->getId(),
      DEBUGGER_ERROR_INVALID_COMMAND));
    theCurrentMessage->setReplyMessage(lReply.release());
    return;
  }
  switch (theCurrentMessage->getCommand())
  {
  case VARIABLES:
    theCurrentMessage->setReplyMessage(getAllVariables());
    break;
  case EVAL:
    evalCommand();
    break;
  }
}

void ZorbaDebuggerRuntime::setQueryRunning()
{
  AutoLock lLock(theLock, Lock::WRITE);
  assert(theExecStatus == QUERY_RESUMED);
  theExecStatus = QUERY_RUNNING;
}

QueryLoc ZorbaDebuggerRuntime::addBreakpoint(const QueryLoc& aLocation,
                                             unsigned int aId)
{
  AutoLock lLock(theLock, Lock::WRITE);
  DebugLocation_t lLocation;
  lLocation.theFileName = aLocation.getFilename().c_str();
  lLocation.theLineNumber = aLocation.getLineno();
  ZorbaDebuggerCommons* lCommons = theWrapper->thePlanState->theDebuggerCommons;
  if (lCommons->addBreakpoint(lLocation, aId)){
    return lLocation.theQueryLocation;
  }
  return QueryLoc();
}

void ZorbaDebuggerRuntime::suspendRuntime( QueryLoc aLocation, SuspensionCause aCause )
{
  theLock.wlock();
  theExecStatus = QUERY_SUSPENDED;
  std::auto_ptr<SuspendedEvent> lMessage(new SuspendedEvent(aLocation, aCause));
  theCommunicator->sendEvent(lMessage.get());
  lMessage.reset(0);
  theLock.unlock();
  suspend();
}

void ZorbaDebuggerRuntime::resumeQuery()
{
  AutoLock lLock(theLock, Lock::WRITE);
#ifndef NDEBUG
  ResumeMessage* lMessage = dynamic_cast<ResumeMessage*>(theCurrentMessage);
  assert(lMessage);
#endif
  resumeRuntime();
}

void ZorbaDebuggerRuntime::resumeRuntime()
{
  theExecStatus = QUERY_RESUMED;
  resume();
  ResumedEvent lEvent;
  theCommunicator->sendEvent(&lEvent);
}

void ZorbaDebuggerRuntime::terminateRuntime()
{
  AutoLock lLock(theLock, Lock::WRITE);
#ifndef NDEBUG
  TerminateMessage* lMessage = dynamic_cast<TerminateMessage*>(theCurrentMessage);
  assert(lMessage);
#endif
  theWrapper->thePlanState->theHasToQuit = true;
  if (theExecStatus == QUERY_SUSPENDED) {
    resume();
  } else if (theExecStatus == QUERY_IDLE) {
    TerminatedEvent lEvent;
    theCommunicator->sendEvent(&lEvent);
  }
  theExecStatus = QUERY_TERMINATED;
}

ReplyMessage* ZorbaDebuggerRuntime::getAllVariables()
{
  ZorbaDebuggerCommons* lCommons =
    theWrapper->thePlanState->theDebuggerCommons;
  static_context* lContext = lCommons->getCurrentStaticContext();
  std::vector<std::string> lVariables;
  lContext->getVariables(lVariables);
  std::auto_ptr<VariableReply> lReply(
    new VariableReply(theCurrentMessage->getId(), DEBUGGER_NO_ERROR));
  std::vector<std::string>::iterator lIter;
  for (lIter = lVariables.begin(); lIter != lVariables.end(); lIter++) {
    if (*lIter == "local") {
      lReply->addLocal(*(++lIter), *(++lIter));
    } else if (*lIter == "global") {
      lReply->addGlobal(*(++lIter), *(++lIter));
    }
  }
  return lReply.release();
}

void ZorbaDebuggerRuntime::step()
{
#ifndef NDEBUG
  // Check preconditions
  ZORBA_ASSERT(dynamic_cast<StepMessage*>(theCurrentMessage) != NULL);
#endif // NDEBUG
  StepMessage* lMessage = static_cast<StepMessage*>(theCurrentMessage);
  StepCommand lCommand = lMessage->getStepKind();
  ZorbaDebuggerCommons* lCommons = theWrapper->thePlanState->theDebuggerCommons;

  switch (lCommand)
  {
  case STEP_INTO:
    // Resume and then suspend as soon as the next iterator is reached.
    lCommons->setBreak(true, CAUSE_STEP);
    resumeRuntime();
    break;
  case STEP_OUT:
    lCommons->makeStepOut();
    resumeRuntime();
    break;
  case STEP_OVER:
    lCommons->makeStepOver();
    resumeRuntime();
    break;
  }
}

void ZorbaDebuggerRuntime::setNotSendTerminateEvent()
{
  theNotSendTerminateEvent = true;
}

void ZorbaDebuggerRuntime::evalCommand()
{
  ZORBA_ASSERT(dynamic_cast<EvalMessage*>(theCurrentMessage));
  xqpString lExpr = static_cast<EvalMessage*>(theCurrentMessage)->getExpr();
  // This command will care itself about garbage collection - so don't delete
  // it in this method!
  EvalCommand* lCommand = new EvalCommand(
    theWrapper->thePlanState->theDebuggerCommons,
    theCommunicator, lExpr.c_str(), theSerializerOptions,
    theCurrentMessage->getId());
  lCommand->setDeleteAfterRun(true);
  lCommand->start();
}

ReplyMessage* ZorbaDebuggerRuntime::listSource()
{
  ZORBA_ASSERT(dynamic_cast<ListCommand*>(theCurrentMessage));
  ListCommand* lCommand = dynamic_cast<ListCommand*>(theCurrentMessage);
  std::string lFile;
  lFile = theWrapper->thePlanState->theDebuggerCommons->getFilepathOfURI(
    lCommand->getFilename());

  std::string lCurrLine;
  //std::string::iterator lSIter;
  //for (lSIter = lFile.begin(); lSIter != lFile.end(); ++lSIter) {
  //  if (*lSIter == '\\' && *(lSIter+1) == '\\') {
  //    lFile.erase(lSIter);
  //    ++lSIter;
  //  }
  //}
  std::ifstream lStream(lFile.c_str());
  for (unsigned long i = 0; i < lCommand->getFirstline() && lStream.good(); ++i)
  {
    std::getline(lStream, lCurrLine);
  }
  std::stringstream lOut;
  for (unsigned long i = lCommand->getFirstline();
    i < lCommand->getLastline() && lStream.good(); ++i) {
    std::getline(lStream, lCurrLine);
    lOut << lCurrLine;
    if (lStream.good()) {
      lOut << std::endl;
    }
  }
  return new ListReply(
    theCurrentMessage->getId(), DEBUGGER_NO_ERROR, lOut.str());
}

} // namespace zorba
<commit_msg>An older fix during sausalito debugger fixes<commit_after>/*
 * Copyright 2006-2008 The FLWOR 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.
 */
#include "zorba_debugger_runtime.h"

#include <memory>
#include <vector>
#include <sstream>
#include <fstream>

#include "store/api/store.h"

#include "api/zorbaimpl.h"
#include "api/xqueryimpl.h"
#include "api/serializerimpl.h"

#include "context/static_context.h"

#include "runtime/api/plan_wrapper.h"
#include "runtime/debug/zorba_debug_iterator.h"
#include "runtime/util/flowctl_exception.h"

#include "zorba/exception.h"
#include "zorba/printer_error_handler.h"
#include "zorbaerrors/errors.h"

#include "debugger/debugger_protocol.h"
#include "debugger/synchronous_logger.h"
#include "debugger/debugger_communication.h"
#include "debugger/zorba_debugger_commons.h"

#ifdef WIN32
#include <windows.h>
#define sleep(s) Sleep(s*1000)
#endif

namespace zorba {
  class EvalCommand : public Runnable
  {
  public:
    EvalCommand(ZorbaDebuggerCommons* aCommons,
      DebuggerCommunicator* aCommunicator,
      const xqpString& aEvalString,
      Zorba_SerializerOptions& aSerOpts,
      Id aId)
      :
    theCommons(aCommons),
    theCommunicator(aCommunicator),
    theEvalString(aEvalString),
    theSerOpts(aSerOpts),
    theId(aId)
    {}

    virtual ~EvalCommand() {}

    /**
    * @brief runs the evaluation command in the current scope.
    *
    * Runs theEvalString in. This method is supposed to run in its own thread
    * and it will send an evaluation event back to the client after finishing.
    *
    * @pre theCommons != NULL
    * @pre theCommunicator != NULL
    */
    virtual void run()
    {
      // Check preconditions
      ZORBA_ASSERT(theCommons != NULL);
      ZORBA_ASSERT(theCommunicator != NULL);
      std::auto_ptr<EvaluatedEvent> lEvent;

      try {
        lEvent.reset(
          new EvaluatedEvent(
            theId,
            theEvalString,
            theCommons->eval(theEvalString, theSerOpts)));
      } catch (error::ZorbaError& lError) {
        lEvent.reset(
          new EvaluatedEvent(
            theId,
            theEvalString,
            lError.toString()));
      }
      theCommunicator->sendEvent(lEvent.get());
    }

    virtual void finish()
    {
    }

  private:
    ZorbaDebuggerCommons*     theCommons;
    DebuggerCommunicator*     theCommunicator;
    xqpString                 theEvalString;
    Zorba_SerializerOptions&  theSerOpts;
    Id                        theId;
  };

ZorbaDebuggerRuntime::ZorbaDebuggerRuntime(
  XQueryImpl* xqueryImpl,
  std::ostream& oStream,
  Zorba_SerializerOptions& serializerOptions,
  DebuggerCommunicator* communicator,
  itemHandler aHandler,
  void* aCallBackData)
  : theQuery(xqueryImpl),
    theOStream(oStream),
    theSerializerOptions(serializerOptions),
    theCommunicator(communicator),
    theWrapper(theQuery->generateWrapper()),
    theExecStatus(QUERY_IDLE),
    theCurrentMessage(0),
    theNotSendTerminateEvent(false),
    thePlanIsOpen(false),
    theSerializer(0),
    theItemHandler(aHandler),
    theCallbackData(aCallBackData)
{
}

ZorbaDebuggerRuntime::~ZorbaDebuggerRuntime()
{
  delete theSerializer;
}

// this is the main loop of the thread
// the runtime thread terminates if this method finishes
void
ZorbaDebuggerRuntime::run()
{
  theWrapper->open();
  thePlanIsOpen = true;

  std::auto_ptr<StartedEvent> lStarted(new StartedEvent());
  theCommunicator->sendEvent(lStarted.get());
  lStarted.reset(0);

  runQuery();
}

void ZorbaDebuggerRuntime::finish()
{
  if (thePlanIsOpen) {
    theWrapper->close();
  }
  if (!theNotSendTerminateEvent) {
    TerminatedEvent lEvent;
    theCommunicator->sendEvent(&lEvent);
  }
}

void ZorbaDebuggerRuntime::resetRuntime()
{
  theWrapper = theQuery->generateWrapper();
  thePlanIsOpen = false;
  theExecStatus = QUERY_IDLE;
  theNotSendTerminateEvent = false;
  reset();
}

bool ZorbaDebuggerRuntime::processMessage(AbstractCommandMessage* message)
{
  AutoLock lLock(theLock, Lock::WRITE);
  theCurrentMessage = message;

  switch (theCurrentMessage->getCommandSet())
  {
  case EXECUTION:
    if (execCommands()) {
      return true;
    }
    break;
  case BREAKPOINTS:
    breakpointCommands();
    break;
  case STATIC:
    staticCommands();
    break;
  case DYNAMIC:
    dynamicCommands();
    break;
  default:
    throw InvalidCommandException("Internal Error: Command set not implemented");
  }
  return false;
}

ExecutionStatus ZorbaDebuggerRuntime::getExecutionStatus() const
{
  AutoLock lLock(theLock, Lock::READ);
  return theExecStatus;
}

void ZorbaDebuggerRuntime::runQuery()
{
  theLock.wlock();
  theExecStatus = theExecStatus == QUERY_SUSPENDED ? QUERY_RESUMED : QUERY_RUNNING;

  // used to print error messages
  PrinterErrorHandler lErrorHandler(theOStream);

  try {
    theWrapper->thePlanState->theDebuggerCommons->setRuntime(this);
    theLock.unlock();

    delete theSerializer;
    theSerializer = new serializer(theQuery->theErrorManager);
    SerializerImpl::setSerializationParameters(
      *theSerializer, theSerializerOptions);
    if (theItemHandler) {
      theSerializer->serialize((intern::Serializable*)theWrapper, theOStream,
        theItemHandler, theCallbackData);
    } else {
      theSerializer->serialize((intern::Serializable*)theWrapper, theOStream);
    }

    theOStream.flush();
  } catch (FlowCtlException&) {
    // Runtime correctly terminated by user interrupt
  } catch (error::ZorbaError& e){
    // this does not rethrow but only print the error message
    ZorbaImpl::notifyError(&lErrorHandler, e);
  }
  theLock.wlock();
  theExecStatus = QUERY_TERMINATED;
  theLock.unlock();
}

bool
ZorbaDebuggerRuntime::execCommands()
{
  switch (theCurrentMessage->getCommand())
  {
  case RESUME:
    resumeQuery();
    break;
  case TERMINATE:
    terminateRuntime();
    return true;
  case STEP:
    step();
    break;
  default:
    assert(false);
  }
  return false;
}

void ZorbaDebuggerRuntime::breakpointCommands()
{
  switch (theCurrentMessage->getCommand())
  {
  case SET:
    {
      SetMessage* lMessage;
#ifndef NDEBUG
      lMessage = dynamic_cast<SetMessage*>(theCurrentMessage);
      assert(lMessage);
#else
      lMessage = static_cast<SetMessage*>(theCurrentMessage);
#endif
      std::auto_ptr<SetReply> lReply(new SetReply(theCurrentMessage->getId(), DEBUGGER_NO_ERROR));
      std::map<unsigned int, QueryLoc> lLocations = lMessage->getLocations();
      std::map<unsigned int, QueryLoc>::iterator lIter;
      for (lIter = lLocations.begin(); lIter != lLocations.end(); lIter++) {
        QueryLoc lLoc = addBreakpoint(lIter->second, lIter->first);
        lReply->addBreakpoint(lIter->first, lLoc);
      }
      theCurrentMessage->setReplyMessage(lReply.release());
    }
    break;
  case CLEAR:
    {
      ZORBA_ASSERT(dynamic_cast<ClearMessage*>(theCurrentMessage));
      ClearMessage* lMessage = static_cast<ClearMessage*>(theCurrentMessage);
      std::vector<unsigned int> lIds = lMessage->getIds();
      std::vector<unsigned int>::iterator lIter;
      for (lIter = lIds.begin(); lIter != lIds.end(); ++lIter) {
        ZorbaDebuggerCommons* lCommons =
          theWrapper->thePlanState->theDebuggerCommons;
        lCommons->clearBreakpoint(*lIter);
      }
    }
    break;
  }
}

void ZorbaDebuggerRuntime::staticCommands()
{
  switch (theCurrentMessage->getCommand())
  {
  case LIST:
    theCurrentMessage->setReplyMessage(listSource());
    break;
  }
}

void ZorbaDebuggerRuntime::dynamicCommands()
{
  if (theExecStatus != QUERY_SUSPENDED) {
    std::auto_ptr<ReplyMessage> lReply(
      new ReplyMessage(theCurrentMessage->getId(),
      DEBUGGER_ERROR_INVALID_COMMAND));
    theCurrentMessage->setReplyMessage(lReply.release());
    return;
  }
  switch (theCurrentMessage->getCommand())
  {
  case VARIABLES:
    theCurrentMessage->setReplyMessage(getAllVariables());
    break;
  case EVAL:
    evalCommand();
    break;
  }
}

void ZorbaDebuggerRuntime::setQueryRunning()
{
  AutoLock lLock(theLock, Lock::WRITE);
  assert(theExecStatus == QUERY_RESUMED);
  theExecStatus = QUERY_RUNNING;
}

QueryLoc ZorbaDebuggerRuntime::addBreakpoint(const QueryLoc& aLocation,
                                             unsigned int aId)
{
  AutoLock lLock(theLock, Lock::WRITE);
  DebugLocation_t lLocation;
  lLocation.theFileName = aLocation.getFilename().c_str();
  lLocation.theLineNumber = aLocation.getLineno();
  ZorbaDebuggerCommons* lCommons = theWrapper->thePlanState->theDebuggerCommons;
  if (lCommons->addBreakpoint(lLocation, aId)){
    return lLocation.theQueryLocation;
  }
  return QueryLoc();
}

void ZorbaDebuggerRuntime::suspendRuntime( QueryLoc aLocation, SuspensionCause aCause )
{
  theLock.wlock();
  theExecStatus = QUERY_SUSPENDED;
  std::auto_ptr<SuspendedEvent> lMessage(new SuspendedEvent(aLocation, aCause));
  theCommunicator->sendEvent(lMessage.get());
  lMessage.reset(0);
  theLock.unlock();
  suspend();
}

void ZorbaDebuggerRuntime::resumeQuery()
{
  AutoLock lLock(theLock, Lock::WRITE);
#ifndef NDEBUG
  ResumeMessage* lMessage = dynamic_cast<ResumeMessage*>(theCurrentMessage);
  assert(lMessage);
#endif
  resumeRuntime();
}

void ZorbaDebuggerRuntime::resumeRuntime()
{
  theExecStatus = QUERY_RESUMED;
  resume();
  ResumedEvent lEvent;
  theCommunicator->sendEvent(&lEvent);
}

void ZorbaDebuggerRuntime::terminateRuntime()
{
  AutoLock lLock(theLock, Lock::WRITE);
#ifndef NDEBUG
  TerminateMessage* lMessage = dynamic_cast<TerminateMessage*>(theCurrentMessage);
  assert(lMessage);
#endif
  theWrapper->thePlanState->theHasToQuit = true;
  if (theExecStatus == QUERY_SUSPENDED) {
    resume();
  } else if (theExecStatus == QUERY_IDLE) {
    TerminatedEvent lEvent;
    theCommunicator->sendEvent(&lEvent);
  }
  theExecStatus = QUERY_TERMINATED;
}

ReplyMessage* ZorbaDebuggerRuntime::getAllVariables()
{
  ZorbaDebuggerCommons* lCommons =
    theWrapper->thePlanState->theDebuggerCommons;
  static_context* lContext = lCommons->getCurrentStaticContext();
  std::vector<std::string> lVariables;
  lContext->getVariables(lVariables);
  std::auto_ptr<VariableReply> lReply(
    new VariableReply(theCurrentMessage->getId(), DEBUGGER_NO_ERROR));
  std::vector<std::string>::iterator lIter;
  for (lIter = lVariables.begin(); lIter != lVariables.end(); lIter++) {
    if (*lIter == "local") {
      lReply->addLocal(*(++lIter), *(++lIter));
    } else if (*lIter == "global") {
      lReply->addGlobal(*(++lIter), *(++lIter));
    }
  }
  return lReply.release();
}

void ZorbaDebuggerRuntime::step()
{
#ifndef NDEBUG
  // Check preconditions
  ZORBA_ASSERT(dynamic_cast<StepMessage*>(theCurrentMessage) != NULL);
#endif // NDEBUG
  StepMessage* lMessage = static_cast<StepMessage*>(theCurrentMessage);
  StepCommand lCommand = lMessage->getStepKind();
  ZorbaDebuggerCommons* lCommons = theWrapper->thePlanState->theDebuggerCommons;

  switch (lCommand)
  {
  case STEP_INTO:
    // Resume and then suspend as soon as the next iterator is reached.
    lCommons->setBreak(true, CAUSE_STEP);
    resumeRuntime();
    break;
  case STEP_OUT:
    lCommons->makeStepOut();
    resumeRuntime();
    break;
  case STEP_OVER:
    lCommons->makeStepOver();
    resumeRuntime();
    break;
  }
}

void ZorbaDebuggerRuntime::setNotSendTerminateEvent()
{
  theNotSendTerminateEvent = true;
}

void ZorbaDebuggerRuntime::evalCommand()
{
  ZORBA_ASSERT(dynamic_cast<EvalMessage*>(theCurrentMessage));
  xqpString lExpr = static_cast<EvalMessage*>(theCurrentMessage)->getExpr();
  // This command will care itself about garbage collection - so don't delete
  // it in this method!
  EvalCommand* lCommand = new EvalCommand(
    theWrapper->thePlanState->theDebuggerCommons,
    theCommunicator, lExpr.c_str(), theSerializerOptions,
    theCurrentMessage->getId());
  lCommand->setDeleteAfterRun(true);
  lCommand->start();
}

ReplyMessage* ZorbaDebuggerRuntime::listSource()
{
  ZORBA_ASSERT(dynamic_cast<ListCommand*>(theCurrentMessage));
  ListCommand* lCommand = dynamic_cast<ListCommand*>(theCurrentMessage);
  std::string lFile;
  lFile = theWrapper->thePlanState->theDebuggerCommons->getFilepathOfURI(
    lCommand->getFilename());

  std::string lCurrLine;
  //std::string::iterator lSIter;
  //for (lSIter = lFile.begin(); lSIter != lFile.end(); ++lSIter) {
  //  if (*lSIter == '\\' && *(lSIter+1) == '\\') {
  //    lFile.erase(lSIter);
  //    ++lSIter;
  //  }
  //}
  std::ifstream lStream(lFile.c_str());
  for (unsigned long i = 1; i < lCommand->getFirstline() && lStream.good(); ++i)
  {
    std::getline(lStream, lCurrLine);
  }
  std::stringstream lOut;
  for (unsigned long i = lCommand->getFirstline();
    i <= lCommand->getLastline() && lStream.good(); ++i) {
    std::getline(lStream, lCurrLine);
    lOut << lCurrLine;
    if (lStream.good()) {
      lOut << std::endl;
    }
  }
  return new ListReply(
    theCurrentMessage->getId(), DEBUGGER_NO_ERROR, lOut.str());
}

} // namespace zorba
<|endoftext|>


<commit_before>#include <cassert>
#include <cstring>
#include <fstream>
#include <string>
#include <memory>

#include <GraphMol/FileParsers/MolSupplier.h>

#include <sqlite3ext.h>
extern const sqlite3_api_routines *sqlite3_api;

#include "utils.hpp"
#include "sdf_io.hpp"
#include "mol.hpp"

static const int SDF_INDEX_COLUMN = 0;
static const int SDF_MOLECULE_COLUMN = 1;
static const int SDF_FILEPATH_COLUMN = 2;

static int sdfReaderConnect(sqlite3 *db, void */*pAux*/,
                      int /*argc*/, const char * const */*argv*/,
                      sqlite3_vtab **ppVTab,
                      char **pzErr)
{
  int rc = sqlite3_declare_vtab(db, "CREATE TABLE x("
    "idx INTEGER, molecule MOL, "
    "file_path HIDDEN"
    ")");

  if (rc == SQLITE_OK) {
    sqlite3_vtab *vtab = *ppVTab = (sqlite3_vtab *) sqlite3_malloc(sizeof(sqlite3_vtab));
    if (!vtab) {
      rc = SQLITE_NOMEM;
    }
    else {
      memset(vtab, 0, sizeof(sqlite3_vtab));
    }
  }

  if (rc != SQLITE_OK) {
    *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
  }

  return rc;
}

int sdfReaderBestIndex(sqlite3_vtab */*pVTab*/, sqlite3_index_info *pIndexInfo)
{
  // At this time the only arg passed to the SDF parser is the input file path
  // this function is consequently very simple. it might become more complex
  // when/if support for more args/options is implemented.
  int file_path_index = -1;
  for (int index = 0; index < pIndexInfo->nConstraint; ++index) {
    if (pIndexInfo->aConstraint[index].usable == 0) {
      continue;
    }
    if (pIndexInfo->aConstraint[index].iColumn == SDF_FILEPATH_COLUMN &&
        pIndexInfo->aConstraint[index].op == SQLITE_INDEX_CONSTRAINT_EQ) {
      file_path_index = index;
    }
  }
  if (file_path_index < 0) {
    // The SDF file path is not available, or it's not usable,
    // This plan is unusable for this table
    return SQLITE_CONSTRAINT;
  }
  pIndexInfo->idxNum = 1; // Not really meaningful a this time
  pIndexInfo->aConstraintUsage[file_path_index].argvIndex = 1; // will be argv[0] for xFilter
  pIndexInfo->aConstraintUsage[file_path_index].omit = 1; // no need for SQLite to verify
  pIndexInfo->estimatedCost = 1000000;
  return SQLITE_OK;
}

static int sdfReaderDisconnect(sqlite3_vtab *pVTab)
{
  sqlite3_free(pVTab);
  return SQLITE_OK;
}

struct SdfReaderCursor : public sqlite3_vtab_cursor {
  std::unique_ptr<RDKit::ForwardSDMolSupplier> supplier;
  sqlite3_int64 rowid;
  std::unique_ptr<RDKit::ROMol> mol;
};

static int sdfReaderOpen(sqlite3_vtab */*pVTab*/, sqlite3_vtab_cursor **ppCursor)
{
  int rc = SQLITE_OK;
  SdfReaderCursor *pCsr = new SdfReaderCursor; //FIXME
  *ppCursor = (sqlite3_vtab_cursor *)pCsr;
  return rc;
}

static int sdfReaderClose(sqlite3_vtab_cursor *pCursor)
{
  SdfReaderCursor *p = (SdfReaderCursor *)pCursor;
  delete p;
  return SQLITE_OK;
}

static int sdfReaderFilter(sqlite3_vtab_cursor *pCursor, int /*idxNum*/, const char */*idxStr*/,
                     int argc, sqlite3_value **argv)
{
  SdfReaderCursor *p = (SdfReaderCursor *)pCursor;

  if (argc != 1) {
    // at present we always expect the input file path as the only arg
    return SQLITE_ERROR;
  }

  sqlite3_value *arg = argv[0];
  if (sqlite3_value_type(arg) != SQLITE_TEXT) {
    return SQLITE_MISMATCH;
  }

  const char * file_path = (const char *) sqlite3_value_text(arg);
  std::unique_ptr<std::ifstream> pins(new std::ifstream(file_path));
  if (!pins->is_open()) {
    // Maybe log something
    return SQLITE_ERROR;
  }

  p->supplier.reset(new RDKit::ForwardSDMolSupplier(pins.release(), true));
  if (!p->supplier->atEnd()) {
    p->rowid = 1;
    p->mol.reset(p->supplier->next());
  }

  return SQLITE_OK;
}

static int sdfReaderNext(sqlite3_vtab_cursor *pCursor)
{
  SdfReaderCursor * p = (SdfReaderCursor *)pCursor;
  if (!p->supplier->atEnd()) {
    p->rowid += 1;
    p->mol.reset(p->supplier->next());
  }
  return SQLITE_OK;
}

static int sdfReaderEof(sqlite3_vtab_cursor *pCursor)
{
  SdfReaderCursor * p = (SdfReaderCursor *)pCursor;
  return p->supplier->atEnd() ? 1 : 0;
}

static int sdfReaderColumn(sqlite3_vtab_cursor *pCursor, sqlite3_context *ctx, int N)
{
  SdfReaderCursor * p = (SdfReaderCursor *)pCursor;

  switch (N) {
    case 0:
      // row id
      sqlite3_result_int(ctx, p->rowid);
      break;
    case 1:
      // the molecule
      if (p->mol) {
        int rc = SQLITE_OK;
        Blob blob = mol_to_blob(*p->mol, &rc);
        if (rc == SQLITE_OK) {
          sqlite3_result_blob(ctx, blob.data(), blob.size(), SQLITE_TRANSIENT);
        }
        else {
          sqlite3_result_error_code(ctx, rc);
        }
      }
      else {
        sqlite3_result_null(ctx);
      }
      break;
    default:
      assert(!"unexpected column number");
      sqlite3_result_null(ctx);
  }
  return SQLITE_OK;
}

static int sdfReaderRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid)
{
  SdfReaderCursor * p = (SdfReaderCursor *)pCursor;
  *pRowid = p->rowid;
  return SQLITE_OK;
}

/*
** The SDF reader module, collecting the methods that operate on the PeriodicTable vtab
*/
static sqlite3_module sdfReaderModule = {
  0,                           /* iVersion */
  0,                           /* xCreate - create a table */ /* null because eponymous-only */
  sdfReaderConnect,            /* xConnect - connect to an existing table */
  sdfReaderBestIndex,          /* xBestIndex - Determine search strategy */
  sdfReaderDisconnect,         /* xDisconnect - Disconnect from a table */
  0,                           /* xDestroy - Drop a table */
  sdfReaderOpen,               /* xOpen - open a cursor */
  sdfReaderClose,              /* xClose - close a cursor */
  sdfReaderFilter,             /* xFilter - configure scan constraints */
  sdfReaderNext,               /* xNext - advance a cursor */
  sdfReaderEof,                /* xEof */
  sdfReaderColumn,             /* xColumn - read data */
  sdfReaderRowid,              /* xRowid - read data */
  0,                           /* xUpdate - write data */
  0,                           /* xBegin - begin transaction */
  0,                           /* xSync - sync transaction */
  0,                           /* xCommit - commit transaction */
  0,                           /* xRollback - rollback transaction */
  0,                           /* xFindFunction - function overloading */
  0,                           /* xRename - rename the table */
  0,                           /* xSavepoint */
  0,                           /* xRelease */
  0,                           /* xRollbackTo */
  0                            /* xShadowName */
};

int chemicalite_init_sdf_io(sqlite3 *db)
{
  int rc = SQLITE_OK;

  if (rc == SQLITE_OK) {
    rc = sqlite3_create_module_v2(db, "sdf_reader", &sdfReaderModule,
				  0,  /* Client data for xCreate/xConnect */
				  0   /* Module destructor function */
				  );
  }

  return rc;
}
<commit_msg>comment-out two unused variables<commit_after>#include <cassert>
#include <cstring>
#include <fstream>
#include <string>
#include <memory>

#include <GraphMol/FileParsers/MolSupplier.h>

#include <sqlite3ext.h>
extern const sqlite3_api_routines *sqlite3_api;

#include "utils.hpp"
#include "sdf_io.hpp"
#include "mol.hpp"

// static const int SDF_INDEX_COLUMN = 0;
// static const int SDF_MOLECULE_COLUMN = 1;
static const int SDF_FILEPATH_COLUMN = 2;

static int sdfReaderConnect(sqlite3 *db, void */*pAux*/,
                      int /*argc*/, const char * const */*argv*/,
                      sqlite3_vtab **ppVTab,
                      char **pzErr)
{
  int rc = sqlite3_declare_vtab(db, "CREATE TABLE x("
    "idx INTEGER, molecule MOL, "
    "file_path HIDDEN"
    ")");

  if (rc == SQLITE_OK) {
    sqlite3_vtab *vtab = *ppVTab = (sqlite3_vtab *) sqlite3_malloc(sizeof(sqlite3_vtab));
    if (!vtab) {
      rc = SQLITE_NOMEM;
    }
    else {
      memset(vtab, 0, sizeof(sqlite3_vtab));
    }
  }

  if (rc != SQLITE_OK) {
    *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
  }

  return rc;
}

int sdfReaderBestIndex(sqlite3_vtab */*pVTab*/, sqlite3_index_info *pIndexInfo)
{
  // At this time the only arg passed to the SDF parser is the input file path
  // this function is consequently very simple. it might become more complex
  // when/if support for more args/options is implemented.
  int file_path_index = -1;
  for (int index = 0; index < pIndexInfo->nConstraint; ++index) {
    if (pIndexInfo->aConstraint[index].usable == 0) {
      continue;
    }
    if (pIndexInfo->aConstraint[index].iColumn == SDF_FILEPATH_COLUMN &&
        pIndexInfo->aConstraint[index].op == SQLITE_INDEX_CONSTRAINT_EQ) {
      file_path_index = index;
    }
  }
  if (file_path_index < 0) {
    // The SDF file path is not available, or it's not usable,
    // This plan is unusable for this table
    return SQLITE_CONSTRAINT;
  }
  pIndexInfo->idxNum = 1; // Not really meaningful a this time
  pIndexInfo->aConstraintUsage[file_path_index].argvIndex = 1; // will be argv[0] for xFilter
  pIndexInfo->aConstraintUsage[file_path_index].omit = 1; // no need for SQLite to verify
  pIndexInfo->estimatedCost = 1000000;
  return SQLITE_OK;
}

static int sdfReaderDisconnect(sqlite3_vtab *pVTab)
{
  sqlite3_free(pVTab);
  return SQLITE_OK;
}

struct SdfReaderCursor : public sqlite3_vtab_cursor {
  std::unique_ptr<RDKit::ForwardSDMolSupplier> supplier;
  sqlite3_int64 rowid;
  std::unique_ptr<RDKit::ROMol> mol;
};

static int sdfReaderOpen(sqlite3_vtab */*pVTab*/, sqlite3_vtab_cursor **ppCursor)
{
  int rc = SQLITE_OK;
  SdfReaderCursor *pCsr = new SdfReaderCursor; //FIXME
  *ppCursor = (sqlite3_vtab_cursor *)pCsr;
  return rc;
}

static int sdfReaderClose(sqlite3_vtab_cursor *pCursor)
{
  SdfReaderCursor *p = (SdfReaderCursor *)pCursor;
  delete p;
  return SQLITE_OK;
}

static int sdfReaderFilter(sqlite3_vtab_cursor *pCursor, int /*idxNum*/, const char */*idxStr*/,
                     int argc, sqlite3_value **argv)
{
  SdfReaderCursor *p = (SdfReaderCursor *)pCursor;

  if (argc != 1) {
    // at present we always expect the input file path as the only arg
    return SQLITE_ERROR;
  }

  sqlite3_value *arg = argv[0];
  if (sqlite3_value_type(arg) != SQLITE_TEXT) {
    return SQLITE_MISMATCH;
  }

  const char * file_path = (const char *) sqlite3_value_text(arg);
  std::unique_ptr<std::ifstream> pins(new std::ifstream(file_path));
  if (!pins->is_open()) {
    // Maybe log something
    return SQLITE_ERROR;
  }

  p->supplier.reset(new RDKit::ForwardSDMolSupplier(pins.release(), true));
  if (!p->supplier->atEnd()) {
    p->rowid = 1;
    p->mol.reset(p->supplier->next());
  }

  return SQLITE_OK;
}

static int sdfReaderNext(sqlite3_vtab_cursor *pCursor)
{
  SdfReaderCursor * p = (SdfReaderCursor *)pCursor;
  if (!p->supplier->atEnd()) {
    p->rowid += 1;
    p->mol.reset(p->supplier->next());
  }
  return SQLITE_OK;
}

static int sdfReaderEof(sqlite3_vtab_cursor *pCursor)
{
  SdfReaderCursor * p = (SdfReaderCursor *)pCursor;
  return p->supplier->atEnd() ? 1 : 0;
}

static int sdfReaderColumn(sqlite3_vtab_cursor *pCursor, sqlite3_context *ctx, int N)
{
  SdfReaderCursor * p = (SdfReaderCursor *)pCursor;

  switch (N) {
    case 0:
      // row id
      sqlite3_result_int(ctx, p->rowid);
      break;
    case 1:
      // the molecule
      if (p->mol) {
        int rc = SQLITE_OK;
        Blob blob = mol_to_blob(*p->mol, &rc);
        if (rc == SQLITE_OK) {
          sqlite3_result_blob(ctx, blob.data(), blob.size(), SQLITE_TRANSIENT);
        }
        else {
          sqlite3_result_error_code(ctx, rc);
        }
      }
      else {
        sqlite3_result_null(ctx);
      }
      break;
    default:
      assert(!"unexpected column number");
      sqlite3_result_null(ctx);
  }
  return SQLITE_OK;
}

static int sdfReaderRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid)
{
  SdfReaderCursor * p = (SdfReaderCursor *)pCursor;
  *pRowid = p->rowid;
  return SQLITE_OK;
}

/*
** The SDF reader module, collecting the methods that operate on the PeriodicTable vtab
*/
static sqlite3_module sdfReaderModule = {
  0,                           /* iVersion */
  0,                           /* xCreate - create a table */ /* null because eponymous-only */
  sdfReaderConnect,            /* xConnect - connect to an existing table */
  sdfReaderBestIndex,          /* xBestIndex - Determine search strategy */
  sdfReaderDisconnect,         /* xDisconnect - Disconnect from a table */
  0,                           /* xDestroy - Drop a table */
  sdfReaderOpen,               /* xOpen - open a cursor */
  sdfReaderClose,              /* xClose - close a cursor */
  sdfReaderFilter,             /* xFilter - configure scan constraints */
  sdfReaderNext,               /* xNext - advance a cursor */
  sdfReaderEof,                /* xEof */
  sdfReaderColumn,             /* xColumn - read data */
  sdfReaderRowid,              /* xRowid - read data */
  0,                           /* xUpdate - write data */
  0,                           /* xBegin - begin transaction */
  0,                           /* xSync - sync transaction */
  0,                           /* xCommit - commit transaction */
  0,                           /* xRollback - rollback transaction */
  0,                           /* xFindFunction - function overloading */
  0,                           /* xRename - rename the table */
  0,                           /* xSavepoint */
  0,                           /* xRelease */
  0,                           /* xRollbackTo */
  0                            /* xShadowName */
};

int chemicalite_init_sdf_io(sqlite3 *db)
{
  int rc = SQLITE_OK;

  if (rc == SQLITE_OK) {
    rc = sqlite3_create_module_v2(db, "sdf_reader", &sdfReaderModule,
				  0,  /* Client data for xCreate/xConnect */
				  0   /* Module destructor function */
				  );
  }

  return rc;
}
<|endoftext|>


<commit_before>/************************************************************************************
**
* @copyright (c) 2013-2100, ChengDu Duyer Technology Co., LTD. All Right Reserved.
*
*************************************************************************************/
/**
* @file		g_usage.cpp
* @version
* @brief
* @author	duye
* @date		2014-09-30
* @note
*
*  1. 2014-09-30 duye Created this file
*
*/
#include <g_usage.h>

namespace gcom {

}
<commit_msg>Update g_usage.cpp<commit_after>/************************************************************************************
**
* @copyright (c) 2013-2100, ChengDu Duyer Technology Co., LTD. All Right Reserved.
*
*************************************************************************************/
/**
* @file	    g_usage.cpp
* @version
* @brief
* @author   duye
* @date	    2014-09-30
* @note
*
*  1. 2014-09-30 duye Created this file
*
*/
#include <g_usage.h>

namespace gcom {

}
<|endoftext|>