<commit_before>#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <iostream>
#include <boost/algorithm/string.hpp>
#include <gflags/gflags.h>
#include "sort_file.h"
#include "logging.h"

DEFINE_string(mode, "read", "work mode: read/write/seek");
DEFINE_string(file, "", "file path, use ',' to seperate multiple files");
DEFINE_string(start, "", "start key, in 'read' mode");
DEFINE_string(end, "", "end key, in 'read' mode");
DEFINE_string(fs, "hdfs", "filesytem: 'hdfs' or 'local' ");

using baidu::common::Log;
using baidu::common::FATAL;
using baidu::common::INFO;
using baidu::common::WARNING;
using namespace baidu::shuttle;

char g_line_buf[40960];
FileType g_file_type;

void DoRead() {
    std::vector<std::string> file_names;
    boost::split(file_names, FLAGS_file,
                 boost::is_any_of(","), boost::token_compress_on);
    if (file_names.size() == 0 || FLAGS_file.empty()) {
        std::cerr << "use -file to specify input files" << std::endl;
        exit(-1);
    }
    MergeFileReader* reader = new MergeFileReader();
    FileSystem::Param param; //TODO
    Status status = reader->Open(file_names, param, g_file_type);
    if (status != kOk) {
        std::cerr << "fail to open: " << FLAGS_file << std::endl;
        exit(-1);
    }
    SortFileReader::Iterator* it = reader->Scan(FLAGS_start, FLAGS_end);
    if (it->Error() != kOk && it->Error() != kNoMore) {
        std::cerr << "fail top scan: " << FLAGS_file
                  << ", " << Status_Name(it->Error()) << std::endl;
        exit(-1);
    }
    while (!it->Done()) {
        if (it->Error() != kOk && it->Error() != kNoMore) {
            std::cerr << "error happen in reading: "
                      << FLAGS_file
                      << Status_Name(it->Error()) << std::endl;
            exit(-2);
        }
        std::cout << it->Key() << "\t" << it->Value() << std::endl;
        it->Next();
    }
    delete it;
    status = reader->Close();
    if (status != kOk) {
        std::cerr << "fail to close: "
                  <<FLAGS_file
                  << Status_Name(status) << std::endl;
        exit(-1);
    }
    std::cerr << "== Read Done ==" << std::endl;
    return;
}

void DoWrite() {
    if (FLAGS_file.empty()) {
        std::cerr << "use -file to specify output file" << std::endl;
        exit(-1);
    }
    Status status;
    SortFileWriter * writer = SortFileWriter::Create(g_file_type, &status);
    if (status != kOk) {
        std::cerr << "fail to create writer" << std::endl;
        exit(-1);
    }
    FileSystem::Param param; //TODO
    status = writer->Open(FLAGS_file, param);
    if (status != kOk) {
        std::cerr << "fail to open for write:" << FLAGS_file << std::endl;
        exit(-1);
    }
    std::cerr << "Enter: key [tab] value per line" << std::endl;
    int count = 0;
    while (!feof(stdin)) {
        if (fgets(g_line_buf, sizeof(g_line_buf), stdin) ==  NULL) {
            break;
        }
        int span = strcspn(g_line_buf, "\t");
        std::string line(g_line_buf);
        if (line.size() > 0 && line[line.size()-1] == '\n') {
            line.erase(line.size() - 1);
        }
        std::string key = line.substr(0, span);
        std::string value = line.substr(span + 1);
        status = writer->Put(key, value);
        if (status != kOk) {
            std::cerr << "fail to put: "
                      << key << " --> " << value
                      << ", Status:" << Status_Name(status)
                      << std::endl;
            exit(-1);
        }
        if (count % 10000 == 0) {
            std::cerr << "have written " << count << " records" << std::endl;
        }
        count++;
    }
    status = writer->Close();
    if (status != kOk) {
        std::cerr << "fail to close: " << FLAGS_file << std::endl;
        exit(-1);
    }
    std::cerr << "== Write Done ==" << std::endl;
}

void DoSeek() {
    if (FLAGS_file.empty()) {
        std::cerr << "use -file to specify input file" << std::endl;
        exit(-1);
    }
    Status status;
    SortFileReader * reader = SortFileReader::Create(g_file_type, &status);
    if (status != kOk) {
        std::cerr << "fail to create reader" << std::endl;
        exit(-1);
    }
    FileSystem::Param param; //TODO
    status = reader->Open(FLAGS_file, param);
    if (status != kOk) {
        std::cerr << "fail to open for read:" << FLAGS_file << std::endl;
        exit(-1);
    }
    std::cerr << "Enter: key per line" << std::endl;
    while (!feof(stdin)) {
        if (fgets(g_line_buf, sizeof(g_line_buf), stdin) ==  NULL) {
            break;
        }
        int span = strcspn(g_line_buf, "\t");
        std::string line(g_line_buf);
        if (line.size() > 0 && line[line.size()-1] == '\n') {
            line.erase(line.size() - 1);
        }
        std::string key = line.substr(0, span);
        SortFileReader::Iterator* it = reader->Scan(key, key + "\1");
        if (it->Error() != kOk && it->Error() != kNoMore) {
            std::cerr << "fail top scan: " << FLAGS_file
                      << ", " << Status_Name(it->Error()) << std::endl;
            exit(-1);
        }
        int ct = 0;
        while (!it->Done()) {
            if (it->Error() != kOk && it->Error() != kNoMore) {
                std::cerr << "error ocurrs, status: "
                          << Status_Name(it->Error())
                          << std::endl;
            } else {
                std::cout << key << "\t" << it->Value() << std::endl;
                ct++;
            }
            it->Next();
        }
        if (ct == 0 ) {
            std::cerr << key << "\tNOT_FOUND" << std::endl;
        }
        delete it;
    }
    status = reader->Close();
    if (status != kOk) {
        std::cerr << "fail to close: " << FLAGS_file << std::endl;
        exit(-1);
    }
    std::cerr << "== Seek Done ==" << std::endl;
}

int main(int argc, char* argv[]) {
    baidu::common::SetLogFile("./sf_tool.log");
    baidu::common::SetWarningFile("./sf_tool.log.wf");
    google::ParseCommandLineFlags(&argc, &argv, true);
    if (FLAGS_fs == "hdfs") {
        g_file_type = kHdfsFile;
    } else if (FLAGS_fs == "local") {
        g_file_type = kLocalFile;
    } else {
        std::cerr << "unkonw file type: " << FLAGS_fs << std::endl;
        return -1;
    }
    if (FLAGS_mode == "read") {
        DoRead();
    } else if (FLAGS_mode == "write") {
        DoWrite();
    } else if (FLAGS_mode == "seek") {
        DoSeek();
    } else {
        std::cerr << "unkown work mode:" << FLAGS_mode << std::endl;
        return 1;
    }
    return 0;
}
<commit_msg>fix bug of sf_tool<commit_after>#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <iostream>
#include <boost/algorithm/string.hpp>
#include <gflags/gflags.h>
#include "sort_file.h"
#include "logging.h"

DEFINE_string(mode, "read", "work mode: read/write/seek");
DEFINE_string(file, "", "file path, use ',' to seperate multiple files");
DEFINE_string(start, "", "start key, in 'read' mode");
DEFINE_string(end, "", "end key, in 'read' mode");
DEFINE_string(fs, "hdfs", "filesytem: 'hdfs' or 'local' ");

using baidu::common::Log;
using baidu::common::FATAL;
using baidu::common::INFO;
using baidu::common::WARNING;
using namespace baidu::shuttle;

char g_line_buf[40960];
FileType g_file_type;

void DoRead() {
    std::vector<std::string> file_names;
    boost::split(file_names, FLAGS_file,
                 boost::is_any_of(","), boost::token_compress_on);
    if (file_names.size() == 0 || FLAGS_file.empty()) {
        std::cerr << "use -file to specify input files" << std::endl;
        exit(-1);
    }
    MergeFileReader* reader = new MergeFileReader();
    FileSystem::Param param; //TODO
    Status status = reader->Open(file_names, param, g_file_type);
    if (status != kOk) {
        std::cerr << "fail to open: " << FLAGS_file << std::endl;
        exit(-1);
    }
    SortFileReader::Iterator* it = reader->Scan(FLAGS_start, FLAGS_end);
    if (it->Error() != kOk && it->Error() != kNoMore) {
        std::cerr << "fail top scan: " << FLAGS_file
                  << ", " << Status_Name(it->Error()) << std::endl;
        exit(-1);
    }
    while (!it->Done()) {
        if (it->Error() != kOk && it->Error() != kNoMore) {
            std::cerr << "error happen in reading: "
                      << FLAGS_file
                      << Status_Name(it->Error()) << std::endl;
            exit(-2);
        }
        std::cout << it->Key() << "\t" << it->Value() << std::endl;
        it->Next();
    }
    delete it;
    status = reader->Close();
    if (status != kOk) {
        std::cerr << "fail to close: "
                  <<FLAGS_file
                  << Status_Name(status) << std::endl;
        exit(-1);
    }
    std::cerr << "== Read Done ==" << std::endl;
    return;
}

void DoWrite() {
    if (FLAGS_file.empty()) {
        std::cerr << "use -file to specify output file" << std::endl;
        exit(-1);
    }
    Status status;
    SortFileWriter * writer = SortFileWriter::Create(g_file_type, &status);
    if (status != kOk) {
        std::cerr << "fail to create writer" << std::endl;
        exit(-1);
    }
    FileSystem::Param param; //TODO
    status = writer->Open(FLAGS_file, param);
    if (status != kOk) {
        std::cerr << "fail to open for write:" << FLAGS_file << std::endl;
        exit(-1);
    }
    std::cerr << "Enter: key [tab] value per line" << std::endl;
    int count = 0;
    while (!feof(stdin)) {
        if (fgets(g_line_buf, sizeof(g_line_buf), stdin) ==  NULL) {
            break;
        }
        int span = strcspn(g_line_buf, "\t");
        std::string line(g_line_buf);
        if (line.size() > 0 && line[line.size()-1] == '\n') {
            line.erase(line.size() - 1);
        }
        std::string key = line.substr(0, span);
        std::string value;
        if (span + 1 < (int)line.size()) {
            value = line.substr(span + 1);
        }
        status = writer->Put(key, value);
        if (status != kOk) {
            std::cerr << "fail to put: "
                      << key << " --> " << value
                      << ", Status:" << Status_Name(status)
                      << std::endl;
            exit(-1);
        }
        if (count % 10000 == 0) {
            std::cerr << "have written " << count << " records" << std::endl;
        }
        count++;
    }
    status = writer->Close();
    if (status != kOk) {
        std::cerr << "fail to close: " << FLAGS_file << std::endl;
        exit(-1);
    }
    std::cerr << "== Write Done ==" << std::endl;
}

void DoSeek() {
    if (FLAGS_file.empty()) {
        std::cerr << "use -file to specify input file" << std::endl;
        exit(-1);
    }
    Status status;
    SortFileReader * reader = SortFileReader::Create(g_file_type, &status);
    if (status != kOk) {
        std::cerr << "fail to create reader" << std::endl;
        exit(-1);
    }
    FileSystem::Param param; //TODO
    status = reader->Open(FLAGS_file, param);
    if (status != kOk) {
        std::cerr << "fail to open for read:" << FLAGS_file << std::endl;
        exit(-1);
    }
    std::cerr << "Enter: key per line" << std::endl;
    while (!feof(stdin)) {
        if (fgets(g_line_buf, sizeof(g_line_buf), stdin) ==  NULL) {
            break;
        }
        int span = strcspn(g_line_buf, "\t");
        std::string line(g_line_buf);
        if (line.size() > 0 && line[line.size()-1] == '\n') {
            line.erase(line.size() - 1);
        }
        std::string key = line.substr(0, span);
        SortFileReader::Iterator* it = reader->Scan(key, key + "\1");
        if (it->Error() != kOk && it->Error() != kNoMore) {
            std::cerr << "fail top scan: " << FLAGS_file
                      << ", " << Status_Name(it->Error()) << std::endl;
            exit(-1);
        }
        int ct = 0;
        while (!it->Done()) {
            if (it->Error() != kOk && it->Error() != kNoMore) {
                std::cerr << "error ocurrs, status: "
                          << Status_Name(it->Error())
                          << std::endl;
            } else {
                std::cout << key << "\t" << it->Value() << std::endl;
                ct++;
            }
            it->Next();
        }
        if (ct == 0 ) {
            std::cerr << key << "\tNOT_FOUND" << std::endl;
        }
        delete it;
    }
    status = reader->Close();
    if (status != kOk) {
        std::cerr << "fail to close: " << FLAGS_file << std::endl;
        exit(-1);
    }
    std::cerr << "== Seek Done ==" << std::endl;
}

int main(int argc, char* argv[]) {
    baidu::common::SetLogFile("./sf_tool.log");
    baidu::common::SetWarningFile("./sf_tool.log.wf");
    google::ParseCommandLineFlags(&argc, &argv, true);
    if (FLAGS_fs == "hdfs") {
        g_file_type = kHdfsFile;
    } else if (FLAGS_fs == "local") {
        g_file_type = kLocalFile;
    } else {
        std::cerr << "unkonw file type: " << FLAGS_fs << std::endl;
        return -1;
    }
    if (FLAGS_mode == "read") {
        DoRead();
    } else if (FLAGS_mode == "write") {
        DoWrite();
    } else if (FLAGS_mode == "seek") {
        DoSeek();
    } else {
        std::cerr << "unkown work mode:" << FLAGS_mode << std::endl;
        return 1;
    }
    return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2015 Andrew Kelley
 *
 * This file is part of zig, which is MIT licensed.
 * See http://opensource.org/licenses/MIT
 */

#ifndef ZIG_UTIL_HPP
#define ZIG_UTIL_HPP

#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <ctype.h>

#if defined(_MSC_VER)
#include <intrin.h>
#endif

#define ZIG_Q(x) #x
#define ZIG_QUOTE(x) ZIG_Q(x)

#include "util_base.hpp"
#include "heap.hpp"
#include "mem.hpp"

#if defined(_MSC_VER)
static inline int clzll(unsigned long long mask) {
    unsigned long lz;
#if defined(_WIN64)
    if (_BitScanReverse64(&lz, mask))
        return static_cast<int>(63 - lz);
    zig_unreachable();
#else
    if (_BitScanReverse(&lz, mask >> 32))
        lz += 32;
    else
        _BitScanReverse(&lz, mask & 0xffffffff);
    return 63 - lz;
#endif
}
static inline int ctzll(unsigned long long mask) {
    unsigned long result;
#if defined(_WIN64)
    if (_BitScanForward64(&result, mask))
        return result;
    zig_unreachable();
#else
    if (_BitScanForward(&result, mask & 0xffffffff))
        return result;
    }
    if (_BitScanForward(&result, mask >> 32))
        return 32 + result;
    zig_unreachable();
#endif
}
#else
#define clzll(x) __builtin_clzll(x)
#define ctzll(x) __builtin_ctzll(x)
#endif

template <typename T, size_t n>
constexpr size_t array_length(const T (&)[n]) {
    return n;
}

template <typename T>
static inline T max(T a, T b) {
    return (a >= b) ? a : b;
}

template <typename T>
static inline T min(T a, T b) {
    return (a <= b) ? a : b;
}

template<typename T>
static inline T clamp(T min_value, T value, T max_value) {
    return max(min(value, max_value), min_value);
}

static inline bool mem_eql_mem(const char *a_ptr, size_t a_len, const char *b_ptr, size_t b_len) {
    if (a_len != b_len)
        return false;
    return memcmp(a_ptr, b_ptr, a_len) == 0;
}
static inline bool mem_eql_mem_ignore_case(const char *a_ptr, size_t a_len, const char *b_ptr, size_t b_len) {
    if (a_len != b_len)
        return false;
    for (size_t i = 0; i < a_len; i += 1) {
        if (tolower(a_ptr[i]) != tolower(b_ptr[i]))
            return false;
    }
    return true;
}

static inline bool mem_eql_str(const char *mem, size_t mem_len, const char *str) {
    return mem_eql_mem(mem, mem_len, str, strlen(str));
}

static inline bool str_eql_str(const char *a, const char* b) {
    return mem_eql_mem(a, strlen(a), b, strlen(b));
}

static inline bool str_eql_str_ignore_case(const char *a, const char* b) {
    return mem_eql_mem_ignore_case(a, strlen(a), b, strlen(b));
}

static inline bool is_power_of_2(uint64_t x) {
    return x != 0 && ((x & (~x + 1)) == x);
}

static inline bool mem_ends_with_mem(const char *mem, size_t mem_len, const char *end, size_t end_len) {
    if (mem_len < end_len) return false;
    return memcmp(mem + mem_len - end_len, end, end_len) == 0;
}

static inline bool mem_ends_with_str(const char *mem, size_t mem_len, const char *str) {
    return mem_ends_with_mem(mem, mem_len, str, strlen(str));
}

static inline uint64_t round_to_next_power_of_2(uint64_t x) {
    --x;
    x |= x >> 1;
    x |= x >> 2;
    x |= x >> 4;
    x |= x >> 8;
    x |= x >> 16;
    x |= x >> 32;
    return x + 1;
}

uint32_t int_hash(int i);
bool int_eq(int a, int b);
uint32_t uint64_hash(uint64_t i);
bool uint64_eq(uint64_t a, uint64_t b);
uint32_t ptr_hash(const void *ptr);
bool ptr_eq(const void *a, const void *b);

static inline uint8_t log2_u64(uint64_t x) {
    return (63 - clzll(x));
}

void zig_pretty_print_bytes(FILE *f, double n);

template<typename T>
struct Optional {
    T value;
    bool is_some;

    static inline Optional<T> some(T x) {
        return {x, true};
    }

    static inline Optional<T> none() {
        return {{}, false};
    }

    inline bool unwrap(T *res) {
        *res = value;
        return is_some;
    }
};

template<typename T>
struct Slice {
    T *ptr;
    size_t len;

    inline T &at(size_t i) {
        assert(i < len);
        return ptr[i];
    }

    inline Slice<T> slice(size_t start, size_t end) {
        assert(end <= len);
        assert(end >= start);
        return {
            ptr + start,
            end - start,
        };
    }

    inline Slice<T> sliceFrom(size_t start) {
        assert(start <= len);
        return {
            ptr + start,
            len - start,
        };
    }

    static inline Slice<T> alloc(size_t n) {
        return {heap::c_allocator.allocate_nonzero<T>(n), n};
    }
};

template<typename T, size_t n>
struct Array {
    static const size_t len = n;
    T items[n];

    inline Slice<T> slice() {
        return {
            &items[0],
            len,
        };
    }
};

static inline Slice<uint8_t> str(const char *literal) {
    return {(uint8_t*)(literal), strlen(literal)};
}

// Ported from std/mem.zig
template<typename T>
static inline bool memEql(Slice<T> a, Slice<T> b) {
    if (a.len != b.len)
        return false;
    for (size_t i = 0; i < a.len; i += 1) {
        if (a.ptr[i] != b.ptr[i])
            return false;
    }
    return true;
}

// Ported from std/mem.zig
template<typename T>
static inline bool memStartsWith(Slice<T> haystack, Slice<T> needle) {
    if (needle.len > haystack.len)
        return false;
    return memEql(haystack.slice(0, needle.len), needle);
}

// Ported from std/mem.zig
template<typename T>
static inline void memCopy(Slice<T> dest, Slice<T> src) {
    assert(dest.len >= src.len);
    memcpy(dest.ptr, src.ptr, src.len * sizeof(T));
}

// Ported from std/mem.zig.
// Coordinate struct fields with memSplit function
struct SplitIterator {
    size_t index;
    Slice<uint8_t> buffer;
    Slice<uint8_t> split_bytes;
};

bool SplitIterator_isSplitByte(SplitIterator *self, uint8_t byte);
Optional< Slice<uint8_t> > SplitIterator_next(SplitIterator *self);
Optional< Slice<uint8_t> > SplitIterator_next_separate(SplitIterator *self);
Slice<uint8_t> SplitIterator_rest(SplitIterator *self);
SplitIterator memSplit(Slice<uint8_t> buffer, Slice<uint8_t> split_bytes);

#endif
<commit_msg>stage1: Remove stray brace in rarely-tested code path<commit_after>/*
 * Copyright (c) 2015 Andrew Kelley
 *
 * This file is part of zig, which is MIT licensed.
 * See http://opensource.org/licenses/MIT
 */

#ifndef ZIG_UTIL_HPP
#define ZIG_UTIL_HPP

#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <ctype.h>

#if defined(_MSC_VER)
#include <intrin.h>
#endif

#define ZIG_Q(x) #x
#define ZIG_QUOTE(x) ZIG_Q(x)

#include "util_base.hpp"
#include "heap.hpp"
#include "mem.hpp"

#if defined(_MSC_VER)
static inline int clzll(unsigned long long mask) {
    unsigned long lz;
#if defined(_WIN64)
    if (_BitScanReverse64(&lz, mask))
        return static_cast<int>(63 - lz);
    zig_unreachable();
#else
    if (_BitScanReverse(&lz, mask >> 32))
        lz += 32;
    else
        _BitScanReverse(&lz, mask & 0xffffffff);
    return 63 - lz;
#endif
}
static inline int ctzll(unsigned long long mask) {
    unsigned long result;
#if defined(_WIN64)
    if (_BitScanForward64(&result, mask))
        return result;
    zig_unreachable();
#else
    if (_BitScanForward(&result, mask & 0xffffffff))
        return result;
    if (_BitScanForward(&result, mask >> 32))
        return 32 + result;
    zig_unreachable();
#endif
}
#else
#define clzll(x) __builtin_clzll(x)
#define ctzll(x) __builtin_ctzll(x)
#endif

template <typename T, size_t n>
constexpr size_t array_length(const T (&)[n]) {
    return n;
}

template <typename T>
static inline T max(T a, T b) {
    return (a >= b) ? a : b;
}

template <typename T>
static inline T min(T a, T b) {
    return (a <= b) ? a : b;
}

template<typename T>
static inline T clamp(T min_value, T value, T max_value) {
    return max(min(value, max_value), min_value);
}

static inline bool mem_eql_mem(const char *a_ptr, size_t a_len, const char *b_ptr, size_t b_len) {
    if (a_len != b_len)
        return false;
    return memcmp(a_ptr, b_ptr, a_len) == 0;
}
static inline bool mem_eql_mem_ignore_case(const char *a_ptr, size_t a_len, const char *b_ptr, size_t b_len) {
    if (a_len != b_len)
        return false;
    for (size_t i = 0; i < a_len; i += 1) {
        if (tolower(a_ptr[i]) != tolower(b_ptr[i]))
            return false;
    }
    return true;
}

static inline bool mem_eql_str(const char *mem, size_t mem_len, const char *str) {
    return mem_eql_mem(mem, mem_len, str, strlen(str));
}

static inline bool str_eql_str(const char *a, const char* b) {
    return mem_eql_mem(a, strlen(a), b, strlen(b));
}

static inline bool str_eql_str_ignore_case(const char *a, const char* b) {
    return mem_eql_mem_ignore_case(a, strlen(a), b, strlen(b));
}

static inline bool is_power_of_2(uint64_t x) {
    return x != 0 && ((x & (~x + 1)) == x);
}

static inline bool mem_ends_with_mem(const char *mem, size_t mem_len, const char *end, size_t end_len) {
    if (mem_len < end_len) return false;
    return memcmp(mem + mem_len - end_len, end, end_len) == 0;
}

static inline bool mem_ends_with_str(const char *mem, size_t mem_len, const char *str) {
    return mem_ends_with_mem(mem, mem_len, str, strlen(str));
}

static inline uint64_t round_to_next_power_of_2(uint64_t x) {
    --x;
    x |= x >> 1;
    x |= x >> 2;
    x |= x >> 4;
    x |= x >> 8;
    x |= x >> 16;
    x |= x >> 32;
    return x + 1;
}

uint32_t int_hash(int i);
bool int_eq(int a, int b);
uint32_t uint64_hash(uint64_t i);
bool uint64_eq(uint64_t a, uint64_t b);
uint32_t ptr_hash(const void *ptr);
bool ptr_eq(const void *a, const void *b);

static inline uint8_t log2_u64(uint64_t x) {
    return (63 - clzll(x));
}

void zig_pretty_print_bytes(FILE *f, double n);

template<typename T>
struct Optional {
    T value;
    bool is_some;

    static inline Optional<T> some(T x) {
        return {x, true};
    }

    static inline Optional<T> none() {
        return {{}, false};
    }

    inline bool unwrap(T *res) {
        *res = value;
        return is_some;
    }
};

template<typename T>
struct Slice {
    T *ptr;
    size_t len;

    inline T &at(size_t i) {
        assert(i < len);
        return ptr[i];
    }

    inline Slice<T> slice(size_t start, size_t end) {
        assert(end <= len);
        assert(end >= start);
        return {
            ptr + start,
            end - start,
        };
    }

    inline Slice<T> sliceFrom(size_t start) {
        assert(start <= len);
        return {
            ptr + start,
            len - start,
        };
    }

    static inline Slice<T> alloc(size_t n) {
        return {heap::c_allocator.allocate_nonzero<T>(n), n};
    }
};

template<typename T, size_t n>
struct Array {
    static const size_t len = n;
    T items[n];

    inline Slice<T> slice() {
        return {
            &items[0],
            len,
        };
    }
};

static inline Slice<uint8_t> str(const char *literal) {
    return {(uint8_t*)(literal), strlen(literal)};
}

// Ported from std/mem.zig
template<typename T>
static inline bool memEql(Slice<T> a, Slice<T> b) {
    if (a.len != b.len)
        return false;
    for (size_t i = 0; i < a.len; i += 1) {
        if (a.ptr[i] != b.ptr[i])
            return false;
    }
    return true;
}

// Ported from std/mem.zig
template<typename T>
static inline bool memStartsWith(Slice<T> haystack, Slice<T> needle) {
    if (needle.len > haystack.len)
        return false;
    return memEql(haystack.slice(0, needle.len), needle);
}

// Ported from std/mem.zig
template<typename T>
static inline void memCopy(Slice<T> dest, Slice<T> src) {
    assert(dest.len >= src.len);
    memcpy(dest.ptr, src.ptr, src.len * sizeof(T));
}

// Ported from std/mem.zig.
// Coordinate struct fields with memSplit function
struct SplitIterator {
    size_t index;
    Slice<uint8_t> buffer;
    Slice<uint8_t> split_bytes;
};

bool SplitIterator_isSplitByte(SplitIterator *self, uint8_t byte);
Optional< Slice<uint8_t> > SplitIterator_next(SplitIterator *self);
Optional< Slice<uint8_t> > SplitIterator_next_separate(SplitIterator *self);
Slice<uint8_t> SplitIterator_rest(SplitIterator *self);
SplitIterator memSplit(Slice<uint8_t> buffer, Slice<uint8_t> split_bytes);

#endif
<|endoftext|>


<commit_before>#include <xzero/IdleTimeout.h>
#include <xzero/WallClock.h>
#include <xzero/executor/Scheduler.h>
#include <assert.h>

namespace xzero {

IdleTimeout::IdleTimeout(WallClock* clock, Scheduler* scheduler) :
  clock_(clock),
  scheduler_(scheduler),
  timeout_(TimeSpan::Zero),
  fired_(),
  active_(false),
  onTimeout_() {
}

IdleTimeout::~IdleTimeout() {
}

void IdleTimeout::setTimeout(TimeSpan value) {
  timeout_ = value;
}

TimeSpan IdleTimeout::timeout() const {
  return timeout_;
}

void IdleTimeout::setCallback(std::function<void()>&& cb) {
  onTimeout_ = std::move(cb);
}

void IdleTimeout::clearCallback() {
  onTimeout_ = decltype(onTimeout_)();
}

void IdleTimeout::touch() {
  if (isActive()) {
    schedule();
  }
}

void IdleTimeout::activate() {
  assert(onTimeout_ && "No timeout callback defined");
  active_ = true;
  schedule();
}

void IdleTimeout::deactivate() {
  active_ = false;
}

TimeSpan IdleTimeout::elapsed() const {
  if (isActive()) {
    return clock_->get() - fired_;
  } else {
    return TimeSpan::Zero;
  }
}

void IdleTimeout::reschedule() {
  assert(isActive());

  TimeSpan deltaTimeout = timeout_ - (clock_->get() - fired_);
  scheduler_->schedule(deltaTimeout, std::bind(&IdleTimeout::onFired, this));
}

void IdleTimeout::schedule() {
  fired_ = clock_->get();
  scheduler_->schedule(timeout_, std::bind(&IdleTimeout::onFired, this));
}

void IdleTimeout::onFired() {
  if (!active_) {
    return;
  }

  if (elapsed() >= timeout_) {
    active_ = false;
    onTimeout_();
  } else if (isActive()) {
    reschedule();
  }
}

bool IdleTimeout::isActive() const {
  return active_;
}

} // namespace xzero
<commit_msg>IdleTimeout: some debug prints<commit_after>#include <xzero/IdleTimeout.h>
#include <xzero/WallClock.h>
#include <xzero/logging/LogSource.h>
#include <xzero/executor/Scheduler.h>
#include <assert.h>

namespace xzero {

static LogSource idleTimeoutLogger("IdleTimeout");
#define ERROR(msg...) do { idleTimeoutLogger.error(msg); } while (0)
#ifndef NDEBUG
#define TRACE(msg...) do { idleTimeoutLogger.trace(msg); } while (0)
#else
#define TRACE(msg...) do {} while (0)
#endif

IdleTimeout::IdleTimeout(WallClock* clock, Scheduler* scheduler) :
  clock_(clock),
  scheduler_(scheduler),
  timeout_(TimeSpan::Zero),
  fired_(),
  active_(false),
  onTimeout_() {
}

IdleTimeout::~IdleTimeout() {
}

void IdleTimeout::setTimeout(TimeSpan value) {
  timeout_ = value;
}

TimeSpan IdleTimeout::timeout() const {
  return timeout_;
}

void IdleTimeout::setCallback(std::function<void()>&& cb) {
  onTimeout_ = std::move(cb);
}

void IdleTimeout::clearCallback() {
  onTimeout_ = decltype(onTimeout_)();
}

void IdleTimeout::touch() {
  if (isActive()) {
    schedule();
  }
}

void IdleTimeout::activate() {
  assert(onTimeout_ && "No timeout callback defined");
  active_ = true;
  schedule();
}

void IdleTimeout::deactivate() {
  active_ = false;
}

TimeSpan IdleTimeout::elapsed() const {
  if (isActive()) {
    return clock_->get() - fired_;
  } else {
    return TimeSpan::Zero;
  }
}

void IdleTimeout::reschedule() {
  assert(isActive());

  TimeSpan deltaTimeout = timeout_ - (clock_->get() - fired_);
  scheduler_->schedule(deltaTimeout, std::bind(&IdleTimeout::onFired, this));
}

void IdleTimeout::schedule() {
  fired_ = clock_->get();
  scheduler_->schedule(timeout_, std::bind(&IdleTimeout::onFired, this));
}

void IdleTimeout::onFired() {
  TRACE("IdleTimeout(%p).onFired: active=%d", this, active_);
  if (!active_) {
    return;
  }

  if (elapsed() >= timeout_) {
    active_ = false;
    onTimeout_();
  } else if (isActive()) {
    reschedule();
  }
}

bool IdleTimeout::isActive() const {
  return active_;
}

} // namespace xzero
<|endoftext|>


<commit_before>// This file was developed by Thomas Müller <thomas94@gmx.net>.
// It is published under the BSD-style license contained in the LICENSE.txt file.

#include "../include/ImageViewer.h"

#include <iostream>
#include <stdexcept>

#include <nanogui/opengl.h>
#include <nanogui/screen.h>
#include <nanogui/window.h>
#include <nanogui/layout.h>
#include <nanogui/label.h>
#include <nanogui/button.h>
#include <nanogui/textbox.h>
#include <nanogui/slider.h>
#include <nanogui/tabwidget.h>
#include <nanogui/vscrollpanel.h>

#include <Iex.h>

using namespace Eigen;
using namespace nanogui;
using namespace std;

TEV_NAMESPACE_BEGIN

ImageViewer::ImageViewer()
    : nanogui::Screen(Vector2i{1024, 767}, "Viewer") {

    auto screenSplit = new Widget(this);
    screenSplit->setLayout(new BoxLayout{Orientation::Horizontal, Alignment::Fill});

    auto leftSide = new Widget(screenSplit);
    leftSide->setFixedWidth(mMenuWidth);
    leftSide->setLayout(new BoxLayout{Orientation::Vertical, Alignment::Fill, 0, 0});

    mImageCanvas = new ImageCanvas{screenSplit, pixelRatio()};

    performLayout();

    auto tools = new Widget{leftSide};
    tools->setLayout(new BoxLayout{Orientation::Vertical, Alignment::Fill, 5});
    auto b = new Button{tools, "Open image file"};
    b->setCallback([&] {
        string path = file_dialog(
            {
                { "exr",  "OpenEXR image" },
                { "hdr",  "HDR image" },
                { "bmp",  "Bitmap Image File" },
                { "gif",  "Graphics Interchange Format image" },
                { "jpg",  "JPEG image" },
                { "jpeg", "JPEG image" },
                { "pic",  "PIC image" },
                { "png",  "Portable Network Graphics image" },
                { "pnm",  "Portable Any Map image" },
                { "psd",  "PSD image" },
                { "tga",  "Truevision TGA image" },
            },
            false
        );

        if (!path.empty()) {
            tryLoadImage(path, true);
        }
    });

    // Exposure label and slider
    {
        auto spacer = new Widget{leftSide};
        spacer->setHeight(10);

        Widget* panel = new Widget{leftSide};
        panel->setLayout(new BoxLayout{Orientation::Vertical, Alignment::Fill, 5});
        auto label = new Label{panel, "Tonemapping", "sans-bold", 20};
        label->setTooltip(
            "The Exposure Value (EV) scales the brightness of an image prior to tonemapping by 2^EV. "
            "It can be controlled via the GUI, or by pressing E/Shift+E."
        );

        panel = new Widget{leftSide};
        panel->setLayout(new BoxLayout{Orientation::Horizontal, Alignment::Middle, 5});

        mExposureLabel = new Label{panel, "", "sans-bold"};

        mExposureSlider = new Slider{panel};
        mExposureSlider->setRange({-5.0f, 5.0f});
        mExposureSlider->setFixedWidth(mMenuWidth - 50);

        mExposureSlider->setCallback([this](float value) {
            setExposure(value);
        });
        setExposure(0);
    }

    // Image selection
    {
        auto spacer = new Widget{leftSide};
        spacer->setHeight(10);

        auto panel = new Widget{leftSide};
        panel->setLayout(new BoxLayout{Orientation::Vertical, Alignment::Fill, 5});
        auto label = new Label{panel, "Images", "sans-bold", 20};
        label->setTooltip(
            "Select images either by left-clicking on them or by pressing arrow/number keys on your keyboard.\n"
            "Right-clicking an image marks it as the 'reference' image. "
            "While a reference image is set, the currently selected image is not simply displayed, but compared to the reference image."
        );

        mImageScrollContainer = new VScrollPanel{leftSide};
        mImageButtonContainer = new Widget{mImageScrollContainer};
        mImageButtonContainer->setLayout(new BoxLayout{Orientation::Vertical, Alignment::Fill});
        mImageScrollContainer->setFixedWidth(mMenuWidth);
    }

    setResizeCallback([this, screenSplit](Vector2i size) {
        screenSplit->setFixedSize(size);
        mImageCanvas->setFixedSize(size - Vector2i{mMenuWidth, 0});
        mImageScrollContainer->setFixedHeight(size.y() - mImageScrollContainer->position().y());

        performLayout();
    });

    this->setSize(Vector2i(1024, 768));
}

bool ImageViewer::dropEvent(const std::vector<std::string>& filenames) {
    if (Screen::dropEvent(filenames)) {
        return true;
    }

    for (const auto& imageFile : filenames) {
        tryLoadImage(imageFile, true);
    }

    return true;
}

bool ImageViewer::keyboardEvent(int key, int scancode, int action, int modifiers) {
    if (Screen::keyboardEvent(key, scancode, action, modifiers)) {
        return true;
    }

    int amountImages = static_cast<int>(mImageInfos.size());

    if (action == GLFW_PRESS) {
        if (key >= GLFW_KEY_0 && key <= GLFW_KEY_9) {
            int idx = (key - GLFW_KEY_1 + 10) % 10;
            if (idx >= 0 && idx < amountImages) {
                selectImage(idx);
            }
        } else if (key == GLFW_KEY_ESCAPE || key == GLFW_KEY_Q) {
            setVisible(false);
            return true;
        }
    }

    // Hotkeys for changing values like exposure should also respond to repeats
    if (action == GLFW_PRESS || action == GLFW_REPEAT) {
        if (key == GLFW_KEY_E) {
            if (modifiers & GLFW_MOD_SHIFT) {
                setExposure(exposure() - 0.5f);
            } else {
                setExposure(exposure() + 0.5f);
            }
        }

        if (key == GLFW_KEY_LEFT) {
            selectImage((mCurrentImage - 1 + amountImages) % amountImages);
        } else if (key == GLFW_KEY_RIGHT) {
            selectImage((mCurrentImage + 1 + amountImages) % amountImages);
        }
    }

    return false;
}

void ImageViewer::draw(NVGcontext *ctx) {
    Screen::draw(ctx);
}

void ImageViewer::addImage(shared_ptr<Image> image, bool shallSelect) {
    size_t index = mImageInfos.size();

    auto button = new ImageButton{mImageButtonContainer, image->name()};
    button->setSelectedCallback([this,index]() {
        selectImage(index);
    });
    button->setFontSize(15);

    mImageInfos.push_back({
        image,
        button,
    });

    performLayout();

    // First image got added, let's select it.
    if (index == 0 || shallSelect) {
        selectImage(index);
        fitAllImages();
    }
}

void ImageViewer::tryLoadImage(const std::string& filename, bool shallSelect) {
    try {
        addImage(make_shared<Image>(filename), shallSelect);
    } catch (invalid_argument e) {
        tfm::format(cerr, "Could not load image from %s: %s\n", filename, e.what());
    } catch (Iex::BaseExc& e) {
        tfm::format(cerr, "Could not load image from %s: %s\n", filename, e.what());
    }
}

void ImageViewer::selectImage(size_t index) {
    if (index >= mImageInfos.size()) {
        throw invalid_argument{tfm::format("Invalid image index (%d) should be in range [0,%d).", index, mImageInfos.size())};
    }

    for (size_t i = 0; i < mImageInfos.size(); ++i) {
        mImageInfos[i].button->setIsSelected(i == index);
    }

    mCurrentImage = index;
    mImageCanvas->setImage(mImageInfos[mCurrentImage].image);
}

float ImageViewer::exposure() {
    return mExposureSlider->value();
}

void ImageViewer::setExposure(float value) {
    value = round(value, 1.0f);
    mExposureSlider->setValue(value);
    mExposureLabel->setCaption(tfm::format("EV%+.1f", value));

    mImageCanvas->setExposure(value);
}

void ImageViewer::fitAllImages() {
    if (mImageInfos.empty()) {
        return;
    }

    Vector2i maxSize = Vector2i::Zero();
    for (const auto& imageInfo : mImageInfos) {
        maxSize = maxSize.cwiseMax(imageInfo.image->size());
    }

    // Convert from image pixel coordinates to nanogui coordinates.
    maxSize = (maxSize.cast<float>() / pixelRatio()).cast<int>();
    // Take into account the size of the menu on the left.
    maxSize.x() += mMenuWidth;

    // Only increase our current size if we are larger than the default size of the window.
    setSize(mSize.cwiseMax(maxSize));
}

void ImageViewer::maximize() {
    glfwMaximizeWindow(mGLFWWindow);
}

TEV_NAMESPACE_END
<commit_msg>Remove unnecessary performLayout() call<commit_after>// This file was developed by Thomas Müller <thomas94@gmx.net>.
// It is published under the BSD-style license contained in the LICENSE.txt file.

#include "../include/ImageViewer.h"

#include <iostream>
#include <stdexcept>

#include <nanogui/opengl.h>
#include <nanogui/screen.h>
#include <nanogui/window.h>
#include <nanogui/layout.h>
#include <nanogui/label.h>
#include <nanogui/button.h>
#include <nanogui/textbox.h>
#include <nanogui/slider.h>
#include <nanogui/tabwidget.h>
#include <nanogui/vscrollpanel.h>

#include <Iex.h>

using namespace Eigen;
using namespace nanogui;
using namespace std;

TEV_NAMESPACE_BEGIN

ImageViewer::ImageViewer()
    : nanogui::Screen(Vector2i{1024, 767}, "Viewer") {

    auto screenSplit = new Widget(this);
    screenSplit->setLayout(new BoxLayout{Orientation::Horizontal, Alignment::Fill});

    auto leftSide = new Widget(screenSplit);
    leftSide->setFixedWidth(mMenuWidth);
    leftSide->setLayout(new BoxLayout{Orientation::Vertical, Alignment::Fill, 0, 0});

    mImageCanvas = new ImageCanvas{screenSplit, pixelRatio()};

    auto tools = new Widget{leftSide};
    tools->setLayout(new BoxLayout{Orientation::Vertical, Alignment::Fill, 5});
    auto b = new Button{tools, "Open image file"};
    b->setCallback([&] {
        string path = file_dialog(
            {
                { "exr",  "OpenEXR image" },
                { "hdr",  "HDR image" },
                { "bmp",  "Bitmap Image File" },
                { "gif",  "Graphics Interchange Format image" },
                { "jpg",  "JPEG image" },
                { "jpeg", "JPEG image" },
                { "pic",  "PIC image" },
                { "png",  "Portable Network Graphics image" },
                { "pnm",  "Portable Any Map image" },
                { "psd",  "PSD image" },
                { "tga",  "Truevision TGA image" },
            },
            false
        );

        if (!path.empty()) {
            tryLoadImage(path, true);
        }
    });

    // Exposure label and slider
    {
        auto spacer = new Widget{leftSide};
        spacer->setHeight(10);

        Widget* panel = new Widget{leftSide};
        panel->setLayout(new BoxLayout{Orientation::Vertical, Alignment::Fill, 5});
        auto label = new Label{panel, "Tonemapping", "sans-bold", 20};
        label->setTooltip(
            "The Exposure Value (EV) scales the brightness of an image prior to tonemapping by 2^EV. "
            "It can be controlled via the GUI, or by pressing E/Shift+E."
        );

        panel = new Widget{leftSide};
        panel->setLayout(new BoxLayout{Orientation::Horizontal, Alignment::Middle, 5});

        mExposureLabel = new Label{panel, "", "sans-bold"};

        mExposureSlider = new Slider{panel};
        mExposureSlider->setRange({-5.0f, 5.0f});
        mExposureSlider->setFixedWidth(mMenuWidth - 50);

        mExposureSlider->setCallback([this](float value) {
            setExposure(value);
        });
        setExposure(0);
    }

    // Image selection
    {
        auto spacer = new Widget{leftSide};
        spacer->setHeight(10);

        auto panel = new Widget{leftSide};
        panel->setLayout(new BoxLayout{Orientation::Vertical, Alignment::Fill, 5});
        auto label = new Label{panel, "Images", "sans-bold", 20};
        label->setTooltip(
            "Select images either by left-clicking on them or by pressing arrow/number keys on your keyboard.\n"
            "Right-clicking an image marks it as the 'reference' image. "
            "While a reference image is set, the currently selected image is not simply displayed, but compared to the reference image."
        );

        mImageScrollContainer = new VScrollPanel{leftSide};
        mImageButtonContainer = new Widget{mImageScrollContainer};
        mImageButtonContainer->setLayout(new BoxLayout{Orientation::Vertical, Alignment::Fill});
        mImageScrollContainer->setFixedWidth(mMenuWidth);
    }

    setResizeCallback([this, screenSplit](Vector2i size) {
        screenSplit->setFixedSize(size);
        mImageCanvas->setFixedSize(size - Vector2i{mMenuWidth, 0});
        mImageScrollContainer->setFixedHeight(size.y() - mImageScrollContainer->position().y());

        performLayout();
    });

    this->setSize(Vector2i(1024, 768));
}

bool ImageViewer::dropEvent(const std::vector<std::string>& filenames) {
    if (Screen::dropEvent(filenames)) {
        return true;
    }

    for (const auto& imageFile : filenames) {
        tryLoadImage(imageFile, true);
    }

    return true;
}

bool ImageViewer::keyboardEvent(int key, int scancode, int action, int modifiers) {
    if (Screen::keyboardEvent(key, scancode, action, modifiers)) {
        return true;
    }

    int amountImages = static_cast<int>(mImageInfos.size());

    if (action == GLFW_PRESS) {
        if (key >= GLFW_KEY_0 && key <= GLFW_KEY_9) {
            int idx = (key - GLFW_KEY_1 + 10) % 10;
            if (idx >= 0 && idx < amountImages) {
                selectImage(idx);
            }
        } else if (key == GLFW_KEY_ESCAPE || key == GLFW_KEY_Q) {
            setVisible(false);
            return true;
        }
    }

    // Hotkeys for changing values like exposure should also respond to repeats
    if (action == GLFW_PRESS || action == GLFW_REPEAT) {
        if (key == GLFW_KEY_E) {
            if (modifiers & GLFW_MOD_SHIFT) {
                setExposure(exposure() - 0.5f);
            } else {
                setExposure(exposure() + 0.5f);
            }
        }

        if (key == GLFW_KEY_LEFT) {
            selectImage((mCurrentImage - 1 + amountImages) % amountImages);
        } else if (key == GLFW_KEY_RIGHT) {
            selectImage((mCurrentImage + 1 + amountImages) % amountImages);
        }
    }

    return false;
}

void ImageViewer::draw(NVGcontext *ctx) {
    Screen::draw(ctx);
}

void ImageViewer::addImage(shared_ptr<Image> image, bool shallSelect) {
    size_t index = mImageInfos.size();

    auto button = new ImageButton{mImageButtonContainer, image->name()};
    button->setSelectedCallback([this,index]() {
        selectImage(index);
    });
    button->setFontSize(15);

    mImageInfos.push_back({
        image,
        button,
    });

    performLayout();

    // First image got added, let's select it.
    if (index == 0 || shallSelect) {
        selectImage(index);
        fitAllImages();
    }
}

void ImageViewer::tryLoadImage(const std::string& filename, bool shallSelect) {
    try {
        addImage(make_shared<Image>(filename), shallSelect);
    } catch (invalid_argument e) {
        tfm::format(cerr, "Could not load image from %s: %s\n", filename, e.what());
    } catch (Iex::BaseExc& e) {
        tfm::format(cerr, "Could not load image from %s: %s\n", filename, e.what());
    }
}

void ImageViewer::selectImage(size_t index) {
    if (index >= mImageInfos.size()) {
        throw invalid_argument{tfm::format("Invalid image index (%d) should be in range [0,%d).", index, mImageInfos.size())};
    }

    for (size_t i = 0; i < mImageInfos.size(); ++i) {
        mImageInfos[i].button->setIsSelected(i == index);
    }

    mCurrentImage = index;
    mImageCanvas->setImage(mImageInfos[mCurrentImage].image);
}

float ImageViewer::exposure() {
    return mExposureSlider->value();
}

void ImageViewer::setExposure(float value) {
    value = round(value, 1.0f);
    mExposureSlider->setValue(value);
    mExposureLabel->setCaption(tfm::format("EV%+.1f", value));

    mImageCanvas->setExposure(value);
}

void ImageViewer::fitAllImages() {
    if (mImageInfos.empty()) {
        return;
    }

    Vector2i maxSize = Vector2i::Zero();
    for (const auto& imageInfo : mImageInfos) {
        maxSize = maxSize.cwiseMax(imageInfo.image->size());
    }

    // Convert from image pixel coordinates to nanogui coordinates.
    maxSize = (maxSize.cast<float>() / pixelRatio()).cast<int>();
    // Take into account the size of the menu on the left.
    maxSize.x() += mMenuWidth;

    // Only increase our current size if we are larger than the default size of the window.
    setSize(mSize.cwiseMax(maxSize));
}

void ImageViewer::maximize() {
    glfwMaximizeWindow(mGLFWWindow);
}

TEV_NAMESPACE_END
<|endoftext|>


<commit_before>// Copyright (c) 2009-2017 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "glyf.h"

#include <algorithm>
#include <limits>

#include "head.h"
#include "loca.h"
#include "maxp.h"

// glyf - Glyph Data
// http://www.microsoft.com/typography/otspec/glyf.htm

namespace ots {

bool OpenTypeGLYF::ParseFlagsForSimpleGlyph(Buffer &glyph,
                                            uint32_t num_flags,
                                            uint32_t *flag_index,
                                            uint32_t *coordinates_length) {
  uint8_t flag = 0;
  if (!glyph.ReadU8(&flag)) {
    return Error("Can't read flag");
  }

  uint32_t delta = 0;
  if (flag & (1u << 1)) {  // x-Short
    ++delta;
  } else if (!(flag & (1u << 4))) {
    delta += 2;
  }

  if (flag & (1u << 2)) {  // y-Short
    ++delta;
  } else if (!(flag & (1u << 5))) {
    delta += 2;
  }

  /* MS and Apple specs say this bit is reserved and must be set to zero, but
   * Apple spec then contradicts itself and says it should be set on the first
   * contour flag for simple glyphs with overlapping contours:
   * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6AATIntro.html
   * (“Overlapping contours” section) */
  if (flag & (1u << 6) && *flag_index != 0) {
    return Error("Bad glyph flag (%d), "
                 "bit 6 must be set to zero for flag %d", flag, *flag_index);
  }

  if (flag & (1u << 3)) {  // repeat
    if (*flag_index + 1 >= num_flags) {
      return Error("Count too high (%d + 1 >= %d)", *flag_index, num_flags);
    }
    uint8_t repeat = 0;
    if (!glyph.ReadU8(&repeat)) {
      return Error("Can't read repeat value");
    }
    if (repeat == 0) {
      return Error("Zero repeat");
    }
    delta += (delta * repeat);

    *flag_index += repeat;
    if (*flag_index >= num_flags) {
      return Error("Count too high (%d >= %d)", *flag_index, num_flags);
    }
  }

  if (flag & (1u << 7)) {  // reserved flag
    return Error("Bad glyph flag (%d), reserved bit 7 must be set to zero", flag);
  }

  *coordinates_length += delta;
  if (glyph.length() < *coordinates_length) {
    return Error("Glyph coordinates length bigger than glyph length (%d > %d)",
                 *coordinates_length, glyph.length());
  }

  return true;
}

bool OpenTypeGLYF::ParseSimpleGlyph(Buffer &glyph,
                                    int16_t num_contours) {
  // read the end-points array
  uint16_t num_flags = 0;
  for (int i = 0; i < num_contours; ++i) {
    uint16_t tmp_index = 0;
    if (!glyph.ReadU16(&tmp_index)) {
      return Error("Can't read contour index %d", i);
    }
    if (tmp_index == 0xffffu) {
      return Error("Bad contour index %d", i);
    }
    // check if the indices are monotonically increasing
    if (i && (tmp_index + 1 <= num_flags)) {
      return Error("Decreasing contour index %d + 1 <= %d", tmp_index, num_flags);
    }
    num_flags = tmp_index + 1;
  }

  uint16_t bytecode_length = 0;
  if (!glyph.ReadU16(&bytecode_length)) {
    return Error("Can't read bytecode length");
  }

  if (this->maxp->version_1 &&
      this->maxp->max_size_glyf_instructions < bytecode_length) {
    return Error("Bytecode length is bigger than maxp.maxSizeOfInstructions "
        "%d: %d", this->maxp->max_size_glyf_instructions, bytecode_length);
  }

  if (!glyph.Skip(bytecode_length)) {
    return Error("Can't read bytecode of length %d", bytecode_length);
  }

  uint32_t coordinates_length = 0;
  for (uint32_t i = 0; i < num_flags; ++i) {
    if (!ParseFlagsForSimpleGlyph(glyph, num_flags, &i, &coordinates_length)) {
      return Error("Failed to parse glyph flags %d", i);
    }
  }

  if (!glyph.Skip(coordinates_length)) {
    return Error("Glyph too short %d", glyph.length());
  }

  if (glyph.remaining() > 3) {
    // We allow 0-3 bytes difference since gly_length is 4-bytes aligned,
    // zero-padded length.
    Warning("Extra bytes at end of the glyph: %d", glyph.remaining());
  }

  this->iov.push_back(std::make_pair(glyph.buffer(), glyph.offset()));

  return true;
}

#define ARG_1_AND_2_ARE_WORDS    (1u << 0)
#define WE_HAVE_A_SCALE          (1u << 3)
#define MORE_COMPONENTS          (1u << 5)
#define WE_HAVE_AN_X_AND_Y_SCALE (1u << 6)
#define WE_HAVE_A_TWO_BY_TWO     (1u << 7)
#define WE_HAVE_INSTRUCTIONS     (1u << 8)

bool OpenTypeGLYF::ParseCompositeGlyph(Buffer &glyph) {
  uint16_t flags = 0;
  uint16_t gid = 0;
  do {
    if (!glyph.ReadU16(&flags) || !glyph.ReadU16(&gid)) {
      return Error("Can't read composite glyph flags or glyphIndex");
    }

    if (gid >= this->maxp->num_glyphs) {
      return Error("Invalid glyph id used in composite glyph: %d", gid);
    }

    if (flags & ARG_1_AND_2_ARE_WORDS) {
      int16_t argument1;
      int16_t argument2;
      if (!glyph.ReadS16(&argument1) || !glyph.ReadS16(&argument2)) {
        return Error("Can't read argument1 or argument2");
      }
    } else {
      uint8_t argument1;
      uint8_t argument2;
      if (!glyph.ReadU8(&argument1) || !glyph.ReadU8(&argument2)) {
        return Error("Can't read argument1 or argument2");
      }
    }

    if (flags & WE_HAVE_A_SCALE) {
      int16_t scale;
      if (!glyph.ReadS16(&scale)) {
        return Error("Can't read scale");
      }
    } else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) {
      int16_t xscale;
      int16_t yscale;
      if (!glyph.ReadS16(&xscale) || !glyph.ReadS16(&yscale)) {
        return Error("Can't read xscale or yscale");
      }
    } else if (flags & WE_HAVE_A_TWO_BY_TWO) {
      int16_t xscale;
      int16_t scale01;
      int16_t scale10;
      int16_t yscale;
      if (!glyph.ReadS16(&xscale) ||
          !glyph.ReadS16(&scale01) ||
          !glyph.ReadS16(&scale10) ||
          !glyph.ReadS16(&yscale)) {
        return Error("Can't read transform");
      }
    }
  } while (flags & MORE_COMPONENTS);

  if (flags & WE_HAVE_INSTRUCTIONS) {
    uint16_t bytecode_length;
    if (!glyph.ReadU16(&bytecode_length)) {
      return Error("Can't read instructions size");
    }

    if (this->maxp->version_1 &&
        this->maxp->max_size_glyf_instructions < bytecode_length) {
      return Error("Bytecode length is bigger than maxp.maxSizeOfInstructions "
                   "%d: %d",
                   this->maxp->max_size_glyf_instructions, bytecode_length);
    }

    if (!glyph.Skip(bytecode_length)) {
      return Error("Can't read bytecode of length %d", bytecode_length);
    }
  }

  this->iov.push_back(std::make_pair(glyph.buffer(), glyph.offset()));

  return true;
}

bool OpenTypeGLYF::Parse(const uint8_t *data, size_t length) {
  OpenTypeMAXP *maxp = static_cast<OpenTypeMAXP*>(
      GetFont()->GetTypedTable(OTS_TAG_MAXP));
  OpenTypeLOCA *loca = static_cast<OpenTypeLOCA*>(
      GetFont()->GetTypedTable(OTS_TAG_LOCA));
  OpenTypeHEAD *head = static_cast<OpenTypeHEAD*>(
      GetFont()->GetTypedTable(OTS_TAG_HEAD));
  if (!maxp || !loca || !head) {
    return Error("Missing maxp or loca or head table needed by glyf table");
  }

  this->maxp = maxp;

  const unsigned num_glyphs = maxp->num_glyphs;
  std::vector<uint32_t> &offsets = loca->offsets;

  if (offsets.size() != num_glyphs + 1) {
    return Error("Invalide glyph offsets size %ld != %d", offsets.size(), num_glyphs + 1);
  }

  std::vector<uint32_t> resulting_offsets(num_glyphs + 1);
  uint32_t current_offset = 0;

  for (unsigned i = 0; i < num_glyphs; ++i) {
    const unsigned gly_offset = offsets[i];
    // The LOCA parser checks that these values are monotonic
    const unsigned gly_length = offsets[i + 1] - offsets[i];
    if (!gly_length) {
      // this glyph has no outline (e.g. the space charactor)
      resulting_offsets[i] = current_offset;
      continue;
    }

    if (gly_offset >= length) {
      return Error("Glyph %d offset %d too high %ld", i, gly_offset, length);
    }
    // Since these are unsigned types, the compiler is not allowed to assume
    // that they never overflow.
    if (gly_offset + gly_length < gly_offset) {
      return Error("Glyph %d length (%d < 0)!", i, gly_length);
    }
    if (gly_offset + gly_length > length) {
      return Error("Glyph %d length %d too high", i, gly_length);
    }

    Buffer glyph(data + gly_offset, gly_length);

    int16_t num_contours, xmin, ymin, xmax, ymax;
    if (!glyph.ReadS16(&num_contours) ||
        !glyph.ReadS16(&xmin) ||
        !glyph.ReadS16(&ymin) ||
        !glyph.ReadS16(&xmax) ||
        !glyph.ReadS16(&ymax)) {
      return Error("Can't read glyph %d header", i);
    }

    if (num_contours <= -2) {
      // -2, -3, -4, ... are reserved for future use.
      return Error("Bad number of contours %d in glyph %d", num_contours, i);
    }

    // workaround for fonts in http://www.princexml.com/fonts/
    if ((xmin == 32767) &&
        (xmax == -32767) &&
        (ymin == 32767) &&
        (ymax == -32767)) {
      Warning("bad xmin/xmax/ymin/ymax values");
      xmin = xmax = ymin = ymax = 0;
    }

    if (xmin > xmax || ymin > ymax) {
      return Error("Bad bounding box values bl=(%d, %d), tr=(%d, %d) in glyph %d", xmin, ymin, xmax, ymax, i);
    }

    if (num_contours == 0) {
      // This is an empty glyph and shouldn’t have any glyph data, but if it
      // does we will simply ignore it.
      glyph.set_offset(0);
    } else if (num_contours > 0) {
      if (!ParseSimpleGlyph(glyph, num_contours)) {
        return Error("Failed to parse glyph %d", i);
      }
    } else {
      if (!ParseCompositeGlyph(glyph)) {
        return Error("Failed to parse glyph %d", i);
      }
    }

    size_t new_size = glyph.offset();
    resulting_offsets[i] = current_offset;
    // glyphs must be four byte aligned
    // TODO(yusukes): investigate whether this padding is really necessary.
    //                Which part of the spec requires this?
    const unsigned padding = (4 - (new_size & 3)) % 4;
    if (padding) {
      this->iov.push_back(std::make_pair(
          reinterpret_cast<const uint8_t*>("\x00\x00\x00\x00"),
          static_cast<size_t>(padding)));
      new_size += padding;
    }
    current_offset += new_size;
  }
  resulting_offsets[num_glyphs] = current_offset;

  const uint16_t max16 = std::numeric_limits<uint16_t>::max();
  if ((*std::max_element(resulting_offsets.begin(),
                         resulting_offsets.end()) >= (max16 * 2u)) &&
      (head->index_to_loc_format != 1)) {
    head->index_to_loc_format = 1;
  }

  loca->offsets = resulting_offsets;

  if (this->iov.empty()) {
    // As a special case when all glyph in the font are empty, add a zero byte
    // to the table, so that we don’t reject it down the way, and to make the
    // table work on Windows as well.
    // See https://github.com/khaledhosny/ots/issues/52
    static const uint8_t kZero = 0;
    this->iov.push_back(std::make_pair(&kZero, 1));
  }

  return true;
}

bool OpenTypeGLYF::Serialize(OTSStream *out) {
  for (unsigned i = 0; i < this->iov.size(); ++i) {
    if (!out->Write(this->iov[i].first, this->iov[i].second)) {
      return Error("Falied to write glyph %d", i);
    }
  }

  return true;
}

}  // namespace ots
<commit_msg>[glyf] Fix miscalculated maxp.maxSizeOfInstructions<commit_after>// Copyright (c) 2009-2017 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "glyf.h"

#include <algorithm>
#include <limits>

#include "head.h"
#include "loca.h"
#include "maxp.h"

// glyf - Glyph Data
// http://www.microsoft.com/typography/otspec/glyf.htm

namespace ots {

bool OpenTypeGLYF::ParseFlagsForSimpleGlyph(Buffer &glyph,
                                            uint32_t num_flags,
                                            uint32_t *flag_index,
                                            uint32_t *coordinates_length) {
  uint8_t flag = 0;
  if (!glyph.ReadU8(&flag)) {
    return Error("Can't read flag");
  }

  uint32_t delta = 0;
  if (flag & (1u << 1)) {  // x-Short
    ++delta;
  } else if (!(flag & (1u << 4))) {
    delta += 2;
  }

  if (flag & (1u << 2)) {  // y-Short
    ++delta;
  } else if (!(flag & (1u << 5))) {
    delta += 2;
  }

  /* MS and Apple specs say this bit is reserved and must be set to zero, but
   * Apple spec then contradicts itself and says it should be set on the first
   * contour flag for simple glyphs with overlapping contours:
   * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6AATIntro.html
   * (“Overlapping contours” section) */
  if (flag & (1u << 6) && *flag_index != 0) {
    return Error("Bad glyph flag (%d), "
                 "bit 6 must be set to zero for flag %d", flag, *flag_index);
  }

  if (flag & (1u << 3)) {  // repeat
    if (*flag_index + 1 >= num_flags) {
      return Error("Count too high (%d + 1 >= %d)", *flag_index, num_flags);
    }
    uint8_t repeat = 0;
    if (!glyph.ReadU8(&repeat)) {
      return Error("Can't read repeat value");
    }
    if (repeat == 0) {
      return Error("Zero repeat");
    }
    delta += (delta * repeat);

    *flag_index += repeat;
    if (*flag_index >= num_flags) {
      return Error("Count too high (%d >= %d)", *flag_index, num_flags);
    }
  }

  if (flag & (1u << 7)) {  // reserved flag
    return Error("Bad glyph flag (%d), reserved bit 7 must be set to zero", flag);
  }

  *coordinates_length += delta;
  if (glyph.length() < *coordinates_length) {
    return Error("Glyph coordinates length bigger than glyph length (%d > %d)",
                 *coordinates_length, glyph.length());
  }

  return true;
}

bool OpenTypeGLYF::ParseSimpleGlyph(Buffer &glyph,
                                    int16_t num_contours) {
  // read the end-points array
  uint16_t num_flags = 0;
  for (int i = 0; i < num_contours; ++i) {
    uint16_t tmp_index = 0;
    if (!glyph.ReadU16(&tmp_index)) {
      return Error("Can't read contour index %d", i);
    }
    if (tmp_index == 0xffffu) {
      return Error("Bad contour index %d", i);
    }
    // check if the indices are monotonically increasing
    if (i && (tmp_index + 1 <= num_flags)) {
      return Error("Decreasing contour index %d + 1 <= %d", tmp_index, num_flags);
    }
    num_flags = tmp_index + 1;
  }

  uint16_t bytecode_length = 0;
  if (!glyph.ReadU16(&bytecode_length)) {
    return Error("Can't read bytecode length");
  }

  if (this->maxp->version_1 &&
      this->maxp->max_size_glyf_instructions < bytecode_length) {
    this->maxp->max_size_glyf_instructions = bytecode_length;
    Warning("Bytecode length is bigger than maxp.maxSizeOfInstructions %d: %d",
            this->maxp->max_size_glyf_instructions, bytecode_length);
  }

  if (!glyph.Skip(bytecode_length)) {
    return Error("Can't read bytecode of length %d", bytecode_length);
  }

  uint32_t coordinates_length = 0;
  for (uint32_t i = 0; i < num_flags; ++i) {
    if (!ParseFlagsForSimpleGlyph(glyph, num_flags, &i, &coordinates_length)) {
      return Error("Failed to parse glyph flags %d", i);
    }
  }

  if (!glyph.Skip(coordinates_length)) {
    return Error("Glyph too short %d", glyph.length());
  }

  if (glyph.remaining() > 3) {
    // We allow 0-3 bytes difference since gly_length is 4-bytes aligned,
    // zero-padded length.
    Warning("Extra bytes at end of the glyph: %d", glyph.remaining());
  }

  this->iov.push_back(std::make_pair(glyph.buffer(), glyph.offset()));

  return true;
}

#define ARG_1_AND_2_ARE_WORDS    (1u << 0)
#define WE_HAVE_A_SCALE          (1u << 3)
#define MORE_COMPONENTS          (1u << 5)
#define WE_HAVE_AN_X_AND_Y_SCALE (1u << 6)
#define WE_HAVE_A_TWO_BY_TWO     (1u << 7)
#define WE_HAVE_INSTRUCTIONS     (1u << 8)

bool OpenTypeGLYF::ParseCompositeGlyph(Buffer &glyph) {
  uint16_t flags = 0;
  uint16_t gid = 0;
  do {
    if (!glyph.ReadU16(&flags) || !glyph.ReadU16(&gid)) {
      return Error("Can't read composite glyph flags or glyphIndex");
    }

    if (gid >= this->maxp->num_glyphs) {
      return Error("Invalid glyph id used in composite glyph: %d", gid);
    }

    if (flags & ARG_1_AND_2_ARE_WORDS) {
      int16_t argument1;
      int16_t argument2;
      if (!glyph.ReadS16(&argument1) || !glyph.ReadS16(&argument2)) {
        return Error("Can't read argument1 or argument2");
      }
    } else {
      uint8_t argument1;
      uint8_t argument2;
      if (!glyph.ReadU8(&argument1) || !glyph.ReadU8(&argument2)) {
        return Error("Can't read argument1 or argument2");
      }
    }

    if (flags & WE_HAVE_A_SCALE) {
      int16_t scale;
      if (!glyph.ReadS16(&scale)) {
        return Error("Can't read scale");
      }
    } else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) {
      int16_t xscale;
      int16_t yscale;
      if (!glyph.ReadS16(&xscale) || !glyph.ReadS16(&yscale)) {
        return Error("Can't read xscale or yscale");
      }
    } else if (flags & WE_HAVE_A_TWO_BY_TWO) {
      int16_t xscale;
      int16_t scale01;
      int16_t scale10;
      int16_t yscale;
      if (!glyph.ReadS16(&xscale) ||
          !glyph.ReadS16(&scale01) ||
          !glyph.ReadS16(&scale10) ||
          !glyph.ReadS16(&yscale)) {
        return Error("Can't read transform");
      }
    }
  } while (flags & MORE_COMPONENTS);

  if (flags & WE_HAVE_INSTRUCTIONS) {
    uint16_t bytecode_length;
    if (!glyph.ReadU16(&bytecode_length)) {
      return Error("Can't read instructions size");
    }

    if (this->maxp->version_1 &&
        this->maxp->max_size_glyf_instructions < bytecode_length) {
      this->maxp->max_size_glyf_instructions = bytecode_length;
      Warning("Bytecode length is bigger than maxp.maxSizeOfInstructions "
              "%d: %d",
              this->maxp->max_size_glyf_instructions, bytecode_length);
    }

    if (!glyph.Skip(bytecode_length)) {
      return Error("Can't read bytecode of length %d", bytecode_length);
    }
  }

  this->iov.push_back(std::make_pair(glyph.buffer(), glyph.offset()));

  return true;
}

bool OpenTypeGLYF::Parse(const uint8_t *data, size_t length) {
  OpenTypeMAXP *maxp = static_cast<OpenTypeMAXP*>(
      GetFont()->GetTypedTable(OTS_TAG_MAXP));
  OpenTypeLOCA *loca = static_cast<OpenTypeLOCA*>(
      GetFont()->GetTypedTable(OTS_TAG_LOCA));
  OpenTypeHEAD *head = static_cast<OpenTypeHEAD*>(
      GetFont()->GetTypedTable(OTS_TAG_HEAD));
  if (!maxp || !loca || !head) {
    return Error("Missing maxp or loca or head table needed by glyf table");
  }

  this->maxp = maxp;

  const unsigned num_glyphs = maxp->num_glyphs;
  std::vector<uint32_t> &offsets = loca->offsets;

  if (offsets.size() != num_glyphs + 1) {
    return Error("Invalide glyph offsets size %ld != %d", offsets.size(), num_glyphs + 1);
  }

  std::vector<uint32_t> resulting_offsets(num_glyphs + 1);
  uint32_t current_offset = 0;

  for (unsigned i = 0; i < num_glyphs; ++i) {
    const unsigned gly_offset = offsets[i];
    // The LOCA parser checks that these values are monotonic
    const unsigned gly_length = offsets[i + 1] - offsets[i];
    if (!gly_length) {
      // this glyph has no outline (e.g. the space charactor)
      resulting_offsets[i] = current_offset;
      continue;
    }

    if (gly_offset >= length) {
      return Error("Glyph %d offset %d too high %ld", i, gly_offset, length);
    }
    // Since these are unsigned types, the compiler is not allowed to assume
    // that they never overflow.
    if (gly_offset + gly_length < gly_offset) {
      return Error("Glyph %d length (%d < 0)!", i, gly_length);
    }
    if (gly_offset + gly_length > length) {
      return Error("Glyph %d length %d too high", i, gly_length);
    }

    Buffer glyph(data + gly_offset, gly_length);

    int16_t num_contours, xmin, ymin, xmax, ymax;
    if (!glyph.ReadS16(&num_contours) ||
        !glyph.ReadS16(&xmin) ||
        !glyph.ReadS16(&ymin) ||
        !glyph.ReadS16(&xmax) ||
        !glyph.ReadS16(&ymax)) {
      return Error("Can't read glyph %d header", i);
    }

    if (num_contours <= -2) {
      // -2, -3, -4, ... are reserved for future use.
      return Error("Bad number of contours %d in glyph %d", num_contours, i);
    }

    // workaround for fonts in http://www.princexml.com/fonts/
    if ((xmin == 32767) &&
        (xmax == -32767) &&
        (ymin == 32767) &&
        (ymax == -32767)) {
      Warning("bad xmin/xmax/ymin/ymax values");
      xmin = xmax = ymin = ymax = 0;
    }

    if (xmin > xmax || ymin > ymax) {
      return Error("Bad bounding box values bl=(%d, %d), tr=(%d, %d) in glyph %d", xmin, ymin, xmax, ymax, i);
    }

    if (num_contours == 0) {
      // This is an empty glyph and shouldn’t have any glyph data, but if it
      // does we will simply ignore it.
      glyph.set_offset(0);
    } else if (num_contours > 0) {
      if (!ParseSimpleGlyph(glyph, num_contours)) {
        return Error("Failed to parse glyph %d", i);
      }
    } else {
      if (!ParseCompositeGlyph(glyph)) {
        return Error("Failed to parse glyph %d", i);
      }
    }

    size_t new_size = glyph.offset();
    resulting_offsets[i] = current_offset;
    // glyphs must be four byte aligned
    // TODO(yusukes): investigate whether this padding is really necessary.
    //                Which part of the spec requires this?
    const unsigned padding = (4 - (new_size & 3)) % 4;
    if (padding) {
      this->iov.push_back(std::make_pair(
          reinterpret_cast<const uint8_t*>("\x00\x00\x00\x00"),
          static_cast<size_t>(padding)));
      new_size += padding;
    }
    current_offset += new_size;
  }
  resulting_offsets[num_glyphs] = current_offset;

  const uint16_t max16 = std::numeric_limits<uint16_t>::max();
  if ((*std::max_element(resulting_offsets.begin(),
                         resulting_offsets.end()) >= (max16 * 2u)) &&
      (head->index_to_loc_format != 1)) {
    head->index_to_loc_format = 1;
  }

  loca->offsets = resulting_offsets;

  if (this->iov.empty()) {
    // As a special case when all glyph in the font are empty, add a zero byte
    // to the table, so that we don’t reject it down the way, and to make the
    // table work on Windows as well.
    // See https://github.com/khaledhosny/ots/issues/52
    static const uint8_t kZero = 0;
    this->iov.push_back(std::make_pair(&kZero, 1));
  }

  return true;
}

bool OpenTypeGLYF::Serialize(OTSStream *out) {
  for (unsigned i = 0; i < this->iov.size(); ++i) {
    if (!out->Write(this->iov[i].first, this->iov[i].second)) {
      return Error("Falied to write glyph %d", i);
    }
  }

  return true;
}

}  // namespace ots
<|endoftext|>


<commit_before>
#include "acrbslam/gps.h"

namespace acrbslam
{

GPS::GPS()
{
	string gps_com_addr=Config::get<string> ( "gps_com_addr" );
	GPS_com_addr=gps_com_addr.c_str();
}

int GPS::gps_com_init(int fd)    //配置串口
{
   struct termios newtio,oldtio;
   tcgetattr(fd,&oldtio);
   bzero(&newtio,sizeof(newtio));

   newtio.c_cflag |=CLOCAL|CREAD;
   /*8N1*/
   newtio.c_cflag &=~CSIZE;
   newtio.c_cflag |= CS8;

   newtio.c_cflag &=~PARENB;

   newtio.c_cflag &= ~CSTOPB;
   /*9600bit/s*/
   cfsetispeed(&newtio,B38400);
   cfsetospeed(&newtio,B38400);
   /*对接收字符和等待时间没有特别要求，刷清输入输出队列*/
   newtio.c_cc[VTIME] = 0;
   newtio.c_cc[VMIN] = 1;
   tcdrain(fd);
   tcflush(fd,TCIOFLUSH);
   /*激活配置*/
   if((tcsetattr(fd,TCSANOW,&newtio))!=0){
      perror("com set error");
      return 0;
   }
   return 1;
}

/*
O_RDONLY      只读模式
O_WRONLY      只写模式
O_RDWR        读写模式

打开/创建文件时，至少得使用上述三个常量中的一个。以下常量是选用的：
O_APPEND       每次写操作都写入文件的末尾
O_CREAT        如果指定文件不存在，则创建这个文件
O_EXCL         如果要创建的文件已存在，则返回 -1，并且修改 errno 的值
O_TRUNC        如果文件存在，并且以只写/读写方式打开，则清空文件全部内容
O_NOCTTY       如果路径名指向终端设备，不要把这个设备用作控制终端。
O_NONBLOCK     如果路径名指向 FIFO/块文件/字符文件，则把文件的打开和后继 I/O设置为非阻塞模式（nonblocking mode）
O_NDELAY       标志通知Linux系统，这个程序不关心DCD信号线所处的状态（端口的另一端是否激活或者停止）。如果用户指定了这个标志，则进程将会一直出在睡眠状态，知道DCD信号线被激活。
以下三个常量同样是选用的，它们用于同步输入输出
O_DSYNC        等待物理 I/O 结束后再 write。在不影响读取新写入的数据的前提下，不等待文件属性更新。
O_RSYNC        read 等待所有写入同一区域的写操作完成后再进行
O_SYNC         等待物理 I/O 结束后再 write，包括更新文件属性的 I/O
*/

double GPS::calcumin(double degree)
{
	double temp = degree/10000000.0;
	double min = (temp -(int)temp)*60;
	return min;
}

double GPS::calcudeg(double degree)
{
	return (int)degree/10000000;
}

void GPS::gps_comu(Data data)
{

	sigset_t              mask;    //主线程中需要把所有的信号屏蔽掉
	int signo;          //用来屏蔽信号
	sigemptyset(&mask);
	sigaddset(&mask, SIGRTMAX-5);
	pthread_sigmask(SIG_BLOCK, &mask, NULL);  //主线程中需要把所有的信号屏蔽掉  如果不屏蔽掉 就会按系统的处理函数运行

	int ttygps;
	/////////////打开惯导串口///////////////////
	if((ttygps = open(GPS_com_addr,O_RDWR|O_NOCTTY|O_NDELAY))==-1){
		perror("打开串口失败");
		//return NULL;
	}
	if(fcntl(ttygps,F_SETFL,0)<0)
		printf("fcntl=%d\n",fcntl(ttygps,F_SETFL,0));
	if(!gps_com_init(ttygps)){
		perror("ttygps串口初始化失败");
		//return NULL;
	}

	/*float lat_deg_base = 4856.3930;
	float lng_deg_base = 12247.4841;*/
	/*double lat_base = 489398830;
	double lng_base = 1227914010;*/
	double lat_base = 391079188;
	double lng_base = 1171730089;

	double lat;
	double lng;
	char temp[96];
	char gpgga[96];

	long sec_base,nsec_base,sec_now,nsec_now;

	long hour_gps,min_gps,sec_gps,temp_gps;

	double time_ms_base = pm_msec();

	while(1){
		sigwait(&mask,&signo);           //等待主线程时钟信号

		double time_ms_now = pm_msec();
		int time_ms_delta = (int)(time_ms_now - time_ms_base);

		int sec_delta,nsec_delta,ms_gps;
		sec_delta = time_ms_delta/1000;
		ms_gps = time_ms_delta -sec_delta*1000;

		hour_gps = sec_delta/3600;
		temp_gps = sec_delta%3600;
		min_gps = temp_gps/60;
		sec_gps = temp_gps%60;

		/*double lat_change = 100.0*(DspData->x_dsp);
		double lng_change = 100.0*(DspData->y_dsp);
		lat = lat_base+lat_change;
		lng = lng_base+lng_change;*/
		float rads = fabs(lat_base)/10000000.0*0.0174532925;
		lat = lat_base+100.0*data.x;
		lng = (lng_base+100.0*data.y);///cos(rads);

		//printf("DspData->x_dsp:%f,DspData->y_dsp:%f,lat_change,%f,lat lng %f,%f,##,%.6f  %.6f\n",DspData->x_dsp,DspData->y_dsp,lat_change,lat,lng,lat/10000000.0,lng/10000000.0);
		//sprintf(temp,"GPGGA,%c%c%c%c%c%c.000,%9.4f,N,%10.4f,W,1,04,0.5,M,19.7,M,,,0000",hour[0],hour[1],min[0],min[1],sec[0],sec[1],lat,lng);
		sprintf(temp,"GPGGA,%02ld%02ld%02ld.%03d,%02.0f%08.5f,N,%03.0f%08.5f,E,1,04,0.5,M,19.7,M,,,0000",hour_gps,min_gps,sec_gps,ms_gps,calcudeg(lat),calcumin(lat),calcudeg(lng),calcumin(lng));
		int ck = 0;
		int i = 0;
		while(temp[i]!='\0'){
			ck^=temp[i];
			i++;
		}
		sprintf(gpgga,"$%s*%2x\r\n",temp,ck);
		//sprintf(gpgga,"$GPGGA,092204.999,4856.3930,S,12247.4841,W,1,04,0.5,M,19.7,M,,,0000*7A\r\n");
		int WriteNum = write(ttygps,(char *)gpgga,strlen(gpgga));
		//printf("%s",gpgga);
		//printf("write_num:%d\n",WriteNum);
    }
    close(ttygps);
}

}//namespace acrbslam
<commit_msg>GPS添加高度，但是转换方式暂未看懂，待修改<commit_after>
#include "acrbslam/gps.h"

namespace acrbslam
{

GPS::GPS()
{
	string gps_com_addr=Config::get<string> ( "gps_com_addr" );
	GPS_com_addr=gps_com_addr.c_str();
}

int GPS::gps_com_init(int fd)    //配置串口
{
   struct termios newtio,oldtio;
   tcgetattr(fd,&oldtio);
   bzero(&newtio,sizeof(newtio));

   newtio.c_cflag |=CLOCAL|CREAD;
   /*8N1*/
   newtio.c_cflag &=~CSIZE;
   newtio.c_cflag |= CS8;

   newtio.c_cflag &=~PARENB;

   newtio.c_cflag &= ~CSTOPB;
   /*9600bit/s*/
   cfsetispeed(&newtio,B38400);
   cfsetospeed(&newtio,B38400);
   /*对接收字符和等待时间没有特别要求，刷清输入输出队列*/
   newtio.c_cc[VTIME] = 0;
   newtio.c_cc[VMIN] = 1;
   tcdrain(fd);
   tcflush(fd,TCIOFLUSH);
   /*激活配置*/
   if((tcsetattr(fd,TCSANOW,&newtio))!=0){
      perror("com set error");
      return 0;
   }
   return 1;
}

/*
O_RDONLY      只读模式
O_WRONLY      只写模式
O_RDWR        读写模式

打开/创建文件时，至少得使用上述三个常量中的一个。以下常量是选用的：
O_APPEND       每次写操作都写入文件的末尾
O_CREAT        如果指定文件不存在，则创建这个文件
O_EXCL         如果要创建的文件已存在，则返回 -1，并且修改 errno 的值
O_TRUNC        如果文件存在，并且以只写/读写方式打开，则清空文件全部内容
O_NOCTTY       如果路径名指向终端设备，不要把这个设备用作控制终端。
O_NONBLOCK     如果路径名指向 FIFO/块文件/字符文件，则把文件的打开和后继 I/O设置为非阻塞模式（nonblocking mode）
O_NDELAY       标志通知Linux系统，这个程序不关心DCD信号线所处的状态（端口的另一端是否激活或者停止）。如果用户指定了这个标志，则进程将会一直出在睡眠状态，知道DCD信号线被激活。
以下三个常量同样是选用的，它们用于同步输入输出
O_DSYNC        等待物理 I/O 结束后再 write。在不影响读取新写入的数据的前提下，不等待文件属性更新。
O_RSYNC        read 等待所有写入同一区域的写操作完成后再进行
O_SYNC         等待物理 I/O 结束后再 write，包括更新文件属性的 I/O
*/

double GPS::calcumin(double degree)
{
	double temp = degree/10000000.0;
	double min = (temp -(int)temp)*60;
	return min;
}

double GPS::calcudeg(double degree)
{
	return (int)degree/10000000;
}

void GPS::gps_comu(Data data)
{

	sigset_t              mask;    //主线程中需要把所有的信号屏蔽掉
	int signo;          //用来屏蔽信号
	sigemptyset(&mask);
	sigaddset(&mask, SIGRTMAX-5);
	pthread_sigmask(SIG_BLOCK, &mask, NULL);  //主线程中需要把所有的信号屏蔽掉  如果不屏蔽掉 就会按系统的处理函数运行

	int ttygps;
	/////////////打开串口///////////////////
	if((ttygps = open(GPS_com_addr,O_RDWR|O_NOCTTY|O_NDELAY))==-1){
		perror("打开串口失败");
		//return NULL;
	}
	if(fcntl(ttygps,F_SETFL,0)<0)
		printf("fcntl=%d\n",fcntl(ttygps,F_SETFL,0));
	//初始化串口
	if(!gps_com_init(ttygps)){
		perror("ttygps串口初始化失败");
		//return NULL;
	}

	/*float lat_deg_base = 4856.3930;
	float lng_deg_base = 12247.4841;*/
	/*double lat_base = 489398830;
	double lng_base = 1227914010;*/
	double lat_base = 391079188;
	double lng_base = 1171730089;

	double lat;
	double lng;
	char temp[96];
	char gpgga[96];

	long sec_base,nsec_base,sec_now,nsec_now;

	long hour_gps,min_gps,sec_gps,temp_gps;

	double time_ms_base = pm_msec();

	while(1){
		sigwait(&mask,&signo);           //等待主线程时钟信号

		double time_ms_now = pm_msec();
		int time_ms_delta = (int)(time_ms_now - time_ms_base);

		int sec_delta,nsec_delta,ms_gps;
		sec_delta = time_ms_delta/1000;
		ms_gps = time_ms_delta -sec_delta*1000;

		hour_gps = sec_delta/3600;
		temp_gps = sec_delta%3600;
		min_gps = temp_gps/60;
		sec_gps = temp_gps%60;

		/*double lat_change = 100.0*(DspData->x_dsp);
		double lng_change = 100.0*(DspData->y_dsp);
		lat = lat_base+lat_change;
		lng = lng_base+lng_change;*/
		float rads = fabs(lat_base)/10000000.0*0.0174532925;
		lat = lat_base+100.0*data.x;
		lng = (lng_base+100.0*data.y);///cos(rads);

		//printf("DspData->x_dsp:%f,DspData->y_dsp:%f,lat_change,%f,lat lng %f,%f,##,%.6f  %.6f\n",DspData->x_dsp,DspData->y_dsp,lat_change,lat,lng,lat/10000000.0,lng/10000000.0);
		//sprintf(temp,"GPGGA,%c%c%c%c%c%c.000,%9.4f,N,%10.4f,W,1,04,0.5,M,19.7,M,,,0000",hour[0],hour[1],min[0],min[1],sec[0],sec[1],lat,lng);
		//sprintf(temp,"GPGGA,%02ld%02ld%02ld.%03d,%02.0f%08.5f,N,%03.0f%08.5f,E,1,04,0.5,M,19.7,M,,,0000",hour_gps,min_gps,sec_gps,ms_gps,calcudeg(lat),calcumin(lat),calcudeg(lng),calcumin(lng));//未添加高度
		sprintf(temp,"GPGGA,%02ld%02ld%02ld.%03d,%02.0f%08.5f,N,%03.0f%08.5f,E,1,04,0.5,%2.5f,M,19.7,M,,,0000",hour_gps,min_gps,sec_gps,ms_gps,calcudeg(lat),calcumin(lat),calcudeg(lng),calcumin(lng),data.z);//添加了高度
		int ck = 0;
		int i = 0;
		while(temp[i]!='\0'){
			ck^=temp[i];
			i++;
		}
		sprintf(gpgga,"$%s*%2x\r\n",temp,ck);
		//sprintf(gpgga,"$GPGGA,092204.999,4856.3930,S,12247.4841,W,1,04,0.5,M,19.7,M,,,0000*7A\r\n");
		int WriteNum = write(ttygps,(char *)gpgga,strlen(gpgga));
		//printf("%s",gpgga);
		//printf("write_num:%d\n",WriteNum);
    }
    close(ttygps);
}

}//namespace acrbslam
<|endoftext|>


<commit_before>/*
* Copyright 2008, 2010 Free Software Foundation, Inc.
*
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU Affero General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Affero General Public License for more details.

	You should have received a copy of the GNU Affero General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/

#include <unistd.h>
#include <fcntl.h>
#include <cstdio>
#include <sys/select.h>

#include "Threads.h"
#include "Sockets.h"
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

#include <string.h>
#include <stdlib.h>

//mutex for protecting non-thread safe gethostbyname
static Mutex sgGethostbynameLock;

bool resolveAddress(struct sockaddr_in *address, const char *hostAndPort)
{
	assert(address);
	assert(hostAndPort);
	char *copy = strdup(hostAndPort);
	char *colon = strchr(copy,':');
	if (!colon) return false;
	*colon = '\0';
	char *host = copy;
	unsigned port = strtol(colon+1,NULL,10);
	bool retVal = resolveAddress(address,host,port);
	free(copy);
	return retVal;
}

bool resolveAddress(struct sockaddr_in *address, const char *host, unsigned short port)
{
	assert(address);
	assert(host);
	//gethostbyname not thread safe
	ScopedLock lock(sgGethostbynameLock);
	// FIXME -- Need to ignore leading/trailing spaces in hostname.
	struct hostent *hp = gethostbyname(host);
	if (hp==NULL) {
		CERR("WARNING -- gethostbyname() failed for " << host << ", " << hstrerror(h_errno));
		return false;
	}
	address->sin_family = AF_INET;
	bcopy(hp->h_addr, &(address->sin_addr), hp->h_length);
	address->sin_port = htons(port);
	return true;
}

DatagramSocket::DatagramSocket()
{
	bzero(mDestination,sizeof(mDestination));
}

void DatagramSocket::nonblocking()
{
	fcntl(mSocketFD,F_SETFL,O_NONBLOCK);
}

void DatagramSocket::blocking()
{
	fcntl(mSocketFD,F_SETFL,0);
}

void DatagramSocket::close()
{
	::close(mSocketFD);
}

DatagramSocket::~DatagramSocket()
{
	close();
}

int DatagramSocket::write( const char * message, size_t length )
{
	assert(length<=MAX_UDP_LENGTH);
	int retVal = sendto(mSocketFD, message, length, 0,
		(struct sockaddr *)mDestination, addressSize());
	if (retVal == -1 ) perror("DatagramSocket::write() failed");
	return retVal;
}

int DatagramSocket::writeBack( const char * message, size_t length )
{
	assert(length<=MAX_UDP_LENGTH);
	int retVal = sendto(mSocketFD, message, length, 0,
		(struct sockaddr *)mSource, addressSize());
	if (retVal == -1 ) perror("DatagramSocket::write() failed");
	return retVal;
}

int DatagramSocket::write( const char * message)
{
	size_t length=strlen(message)+1;
	return write(message,length);
}

int DatagramSocket::writeBack( const char * message)
{
	size_t length=strlen(message)+1;
	return writeBack(message,length);
}

int DatagramSocket::send(const struct sockaddr* dest, const char * message, size_t length )
{
	assert(length<=MAX_UDP_LENGTH);
	int retVal = sendto(mSocketFD, message, length, 0, dest, addressSize());
	if (retVal == -1 ) perror("DatagramSocket::send() failed");
	return retVal;
}

int DatagramSocket::send(const struct sockaddr* dest, const char * message)
{
	size_t length=strlen(message)+1;
	return send(dest,message,length);
}

int DatagramSocket::read(char* buffer)
{
	socklen_t temp_len = sizeof(mSource);
	int length = recvfrom(mSocketFD, (void*)buffer, MAX_UDP_LENGTH, 0,
	    (struct sockaddr*)&mSource,&temp_len);
	if ((length==-1) && (errno!=EAGAIN)) {
		perror("DatagramSocket::read() failed");
		throw SocketError();
	}
	return length;
}

int DatagramSocket::read(char* buffer, unsigned timeout)
{
	fd_set fds;
	FD_SET(mSocketFD,&fds);
	struct timeval tv;
	tv.tv_sec = timeout/1000;
	tv.tv_usec = (timeout%1000)*1000;
	int sel = select(mSocketFD+1,&fds,NULL,NULL,&tv);
	if (sel<0) {
		perror("DatagramSocket::read() select() failed");
		throw SocketError();
	}
	if (sel==0) return -1;
	return read(buffer);
}

UDPSocket::UDPSocket(unsigned short wSrcPort)
	:DatagramSocket()
{
	open(wSrcPort);
}

UDPSocket::UDPSocket(unsigned short wSrcPort,
          	 const char * wDestIP, unsigned short wDestPort )
	:DatagramSocket()
{
	open(wSrcPort);
	destination(wDestPort, wDestIP);
}

void UDPSocket::destination( unsigned short wDestPort, const char * wDestIP )
{
	resolveAddress((sockaddr_in*)mDestination, wDestIP, wDestPort );
}

void UDPSocket::open(unsigned short localPort)
{
	// create
	mSocketFD = socket(AF_INET,SOCK_DGRAM,0);
	if (mSocketFD<0) {
		perror("socket() failed");
		throw SocketError();
	}

	// bind
	struct sockaddr_in address;
	size_t length = sizeof(address);
	bzero(&address,length);
	address.sin_family = AF_INET;
	address.sin_addr.s_addr = INADDR_ANY;
	address.sin_port = htons(localPort);
	if (bind(mSocketFD,(struct sockaddr*)&address,length)<0) {
		perror("bind() failed");
		throw SocketError();
	}
}

unsigned short UDPSocket::port() const
{
	struct sockaddr_in name;
	socklen_t nameSize = sizeof(name);
	int retVal = getsockname(mSocketFD, (struct sockaddr*)&name, &nameSize);
	if (retVal==-1) throw SocketError();
	return ntohs(name.sin_port);
}

UDDSocket::UDDSocket(const char* localPath, const char* remotePath)
	:DatagramSocket()
{
	if (localPath!=NULL) open(localPath);
	if (remotePath!=NULL) destination(remotePath);
}

void UDDSocket::open(const char* localPath)
{
	// create
	mSocketFD = socket(AF_UNIX,SOCK_DGRAM,0);
	if (mSocketFD<0) {
		perror("socket() failed");
		throw SocketError();
	}

	// bind
	struct sockaddr_un address;
	size_t length = sizeof(address);
	bzero(&address,length);
	address.sun_family = AF_UNIX;
	strcpy(address.sun_path,localPath);
	unlink(localPath);
	if (bind(mSocketFD,(struct sockaddr*)&address,length)<0) {
		perror("bind() failed");
		throw SocketError();
	}
}

void UDDSocket::destination(const char* remotePath)
{
	struct sockaddr_un* unAddr = (struct sockaddr_un*)mDestination;
	strcpy(unAddr->sun_path,remotePath);
}

// vim:ts=4:sw=4
<commit_msg>r4408 in private: Add code from David to keep the transceiver running when OpenBTS crashes and check if it is running when starting up.<commit_after>/*
* Copyright 2008, 2010 Free Software Foundation, Inc.
*
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU Affero General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Affero General Public License for more details.

	You should have received a copy of the GNU Affero General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/

#include <unistd.h>
#include <fcntl.h>
#include <cstdio>
#include <sys/select.h>

#include "Threads.h"
#include "Sockets.h"
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

#include <string.h>
#include <stdlib.h>

//mutex for protecting non-thread safe gethostbyname
static Mutex sgGethostbynameLock;

bool resolveAddress(struct sockaddr_in *address, const char *hostAndPort)
{
	assert(address);
	assert(hostAndPort);
	char *copy = strdup(hostAndPort);
	char *colon = strchr(copy,':');
	if (!colon) return false;
	*colon = '\0';
	char *host = copy;
	unsigned port = strtol(colon+1,NULL,10);
	bool retVal = resolveAddress(address,host,port);
	free(copy);
	return retVal;
}

bool resolveAddress(struct sockaddr_in *address, const char *host, unsigned short port)
{
	assert(address);
	assert(host);
	//gethostbyname not thread safe
	ScopedLock lock(sgGethostbynameLock);
	// FIXME -- Need to ignore leading/trailing spaces in hostname.
	struct hostent *hp = gethostbyname(host);
	if (hp==NULL) {
		CERR("WARNING -- gethostbyname() failed for " << host << ", " << hstrerror(h_errno));
		return false;
	}
	address->sin_family = AF_INET;
	bcopy(hp->h_addr, &(address->sin_addr), hp->h_length);
	address->sin_port = htons(port);
	return true;
}

DatagramSocket::DatagramSocket()
{
	bzero(mDestination,sizeof(mDestination));
}

void DatagramSocket::nonblocking()
{
	fcntl(mSocketFD,F_SETFL,O_NONBLOCK);
}

void DatagramSocket::blocking()
{
	fcntl(mSocketFD,F_SETFL,0);
}

void DatagramSocket::close()
{
	::close(mSocketFD);
}

DatagramSocket::~DatagramSocket()
{
	close();
}

int DatagramSocket::write( const char * message, size_t length )
{
	assert(length<=MAX_UDP_LENGTH);
	int retVal = sendto(mSocketFD, message, length, 0,
		(struct sockaddr *)mDestination, addressSize());
	if (retVal == -1 ) perror("DatagramSocket::write() failed");
	return retVal;
}

int DatagramSocket::writeBack( const char * message, size_t length )
{
	assert(length<=MAX_UDP_LENGTH);
	int retVal = sendto(mSocketFD, message, length, 0,
		(struct sockaddr *)mSource, addressSize());
	if (retVal == -1 ) perror("DatagramSocket::write() failed");
	return retVal;
}

int DatagramSocket::write( const char * message)
{
	size_t length=strlen(message)+1;
	return write(message,length);
}

int DatagramSocket::writeBack( const char * message)
{
	size_t length=strlen(message)+1;
	return writeBack(message,length);
}

int DatagramSocket::send(const struct sockaddr* dest, const char * message, size_t length )
{
	assert(length<=MAX_UDP_LENGTH);
	int retVal = sendto(mSocketFD, message, length, 0, dest, addressSize());
	if (retVal == -1 ) perror("DatagramSocket::send() failed");
	return retVal;
}

int DatagramSocket::send(const struct sockaddr* dest, const char * message)
{
	size_t length=strlen(message)+1;
	return send(dest,message,length);
}

int DatagramSocket::read(char* buffer)
{
	socklen_t temp_len = sizeof(mSource);
	int length = recvfrom(mSocketFD, (void*)buffer, MAX_UDP_LENGTH, 0,
	    (struct sockaddr*)&mSource,&temp_len);
	if ((length==-1) && (errno!=EAGAIN)) {
		perror("DatagramSocket::read() failed");
		throw SocketError();
	}
	return length;
}

int DatagramSocket::read(char* buffer, unsigned timeout)
{
	fd_set fds;
	FD_ZERO(&fds);
	struct timeval tv;
	tv.tv_sec = timeout/1000;
	tv.tv_usec = (timeout%1000)*1000;
	int sel = select(mSocketFD+1,&fds,NULL,NULL,&tv);
	if (sel<0) {
		perror("DatagramSocket::read() select() failed");
		throw SocketError();
	}
	if (sel==0) return -1;
	return read(buffer);
}

UDPSocket::UDPSocket(unsigned short wSrcPort)
	:DatagramSocket()
{
	open(wSrcPort);
}

UDPSocket::UDPSocket(unsigned short wSrcPort,
          	 const char * wDestIP, unsigned short wDestPort )
	:DatagramSocket()
{
	open(wSrcPort);
	destination(wDestPort, wDestIP);
}

void UDPSocket::destination( unsigned short wDestPort, const char * wDestIP )
{
	resolveAddress((sockaddr_in*)mDestination, wDestIP, wDestPort );
}

void UDPSocket::open(unsigned short localPort)
{
	// create
	mSocketFD = socket(AF_INET,SOCK_DGRAM,0);
	if (mSocketFD<0) {
		perror("socket() failed");
		throw SocketError();
	}

	// bind
	struct sockaddr_in address;
	size_t length = sizeof(address);
	bzero(&address,length);
	address.sin_family = AF_INET;
	address.sin_addr.s_addr = INADDR_ANY;
	address.sin_port = htons(localPort);
	if (bind(mSocketFD,(struct sockaddr*)&address,length)<0) {
		perror("bind() failed");
		throw SocketError();
	}
}

unsigned short UDPSocket::port() const
{
	struct sockaddr_in name;
	socklen_t nameSize = sizeof(name);
	int retVal = getsockname(mSocketFD, (struct sockaddr*)&name, &nameSize);
	if (retVal==-1) throw SocketError();
	return ntohs(name.sin_port);
}

UDDSocket::UDDSocket(const char* localPath, const char* remotePath)
	:DatagramSocket()
{
	if (localPath!=NULL) open(localPath);
	if (remotePath!=NULL) destination(remotePath);
}

void UDDSocket::open(const char* localPath)
{
	// create
	mSocketFD = socket(AF_UNIX,SOCK_DGRAM,0);
	if (mSocketFD<0) {
		perror("socket() failed");
		throw SocketError();
	}

	// bind
	struct sockaddr_un address;
	size_t length = sizeof(address);
	bzero(&address,length);
	address.sun_family = AF_UNIX;
	strcpy(address.sun_path,localPath);
	unlink(localPath);
	if (bind(mSocketFD,(struct sockaddr*)&address,length)<0) {
		perror("bind() failed");
		throw SocketError();
	}
}

void UDDSocket::destination(const char* remotePath)
{
	struct sockaddr_un* unAddr = (struct sockaddr_un*)mDestination;
	strcpy(unAddr->sun_path,remotePath);
}

// vim:ts=4:sw=4
<|endoftext|>