<commit_before>/*
    Copyright (C) 2001 by Wouter Wijngaards

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

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

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "cssysdef.h"
#include "cssys/sysfunc.h"
#include <windows.h>
#include <stdio.h>
#include <string.h>

bool csGetInstallPath (char *oInstallPath, size_t iBufferSize)
{
  // override the default to get install path from
  // 1. CRYSTAL environment variable
  // 2. this machine's system registry
  // 3. if current working directory contains 'scf.cfg' use this dir.
  // 4. hard-wired default path

  //@@@ this function is called several times; maybe cache the found dir

  // try env variable first
  // we check this before we check registry, so that one app can putenv() to
  // use a special private build of CrystalSpace, while other apps fall back on
  // the shared systemwide registry strategy; this is the best approach unless
  // someone implements a SetInstallPath() to override it before Open() is
  // called.
  if (1)
  {
    char *path = getenv ("CRYSTAL");
    if (path && *path)
    {
      strncpy(oInstallPath, path, iBufferSize);
      goto got_value;
    }
  }

  // try the registry
  if (1)
  {
    char * pValueName = "installpath";
    DWORD dwType;
    DWORD bufSize = iBufferSize;
    HKEY m_pKey;
    LONG result;

    result =
      RegCreateKey(HKEY_LOCAL_MACHINE, "Software\\CrystalSpace", &m_pKey);
    if (result == ERROR_SUCCESS)
    {
      result = RegQueryValueEx(
	m_pKey,
	pValueName,
	0,
	&dwType,
	(unsigned char *)oInstallPath,
	&bufSize);

      if (ERROR_SUCCESS == result)
      {
	goto got_value;
      }
    }
  }

  //@@@ might try GetModuleFilename(NULL,...) here for application's directory

  // perhaps current drive/dir?
  if (1)
  {
    FILE *test = fopen("scf.cfg", "r");
    if(test != NULL)
    {
      // usr current dir
      fclose(test);
      strncpy(oInstallPath, "", iBufferSize);
      goto got_value;
    }
  }

  // nothing helps, use default
  // which is C:\Program Files\Crystal\
  strncpy(oInstallPath, "C:\\Program Files\\Crystal\\", iBufferSize);

got_value:
  // got the value in oInstallPath, check for ending '/' or '\'.
  int len = strlen(oInstallPath);
  if(len == 0) return false;
  if( oInstallPath[len-1] == '/' || oInstallPath[len-1] == '\\' )
    return true;
  if(len+1 >= (int)iBufferSize)
  {
    strncpy(oInstallPath, "", iBufferSize); //make empty if possible
    return false;
  }
  oInstallPath[len] = '\\';
  oInstallPath[len+1] = 0;
  return true;
}
<commit_msg>fixed a "single-line comment containing line-continuation character"<commit_after>/*
    Copyright (C) 2001 by Wouter Wijngaards

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

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

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "cssysdef.h"
#include "cssys/sysfunc.h"
#include <windows.h>
#include <stdio.h>
#include <string.h>

bool csGetInstallPath (char *oInstallPath, size_t iBufferSize)
{
  // override the default to get install path from
  // 1. CRYSTAL environment variable
  // 2. this machine's system registry
  // 3. if current working directory contains 'scf.cfg' use this dir.
  // 4. hard-wired default path

  //@@@ this function is called several times; maybe cache the found dir

  // try env variable first
  // we check this before we check registry, so that one app can putenv() to
  // use a special private build of CrystalSpace, while other apps fall back on
  // the shared systemwide registry strategy; this is the best approach unless
  // someone implements a SetInstallPath() to override it before Open() is
  // called.
  if (1)
  {
    char *path = getenv ("CRYSTAL");
    if (path && *path)
    {
      strncpy(oInstallPath, path, iBufferSize);
      goto got_value;
    }
  }

  // try the registry
  if (1)
  {
    char * pValueName = "installpath";
    DWORD dwType;
    DWORD bufSize = iBufferSize;
    HKEY m_pKey;
    LONG result;

    result =
      RegCreateKey(HKEY_LOCAL_MACHINE, "Software\\CrystalSpace", &m_pKey);
    if (result == ERROR_SUCCESS)
    {
      result = RegQueryValueEx(
	m_pKey,
	pValueName,
	0,
	&dwType,
	(unsigned char *)oInstallPath,
	&bufSize);

      if (ERROR_SUCCESS == result)
      {
	goto got_value;
      }
    }
  }

  //@@@ might try GetModuleFilename(NULL,...) here for application's directory

  // perhaps current drive/dir?
  if (1)
  {
    FILE *test = fopen("scf.cfg", "r");
    if(test != NULL)
    {
      // usr current dir
      fclose(test);
      strncpy(oInstallPath, "", iBufferSize);
      goto got_value;
    }
  }

  // nothing helps, use default
  // which is "C:\Program Files\Crystal\"

  strncpy(oInstallPath, "C:\\Program Files\\Crystal\\", iBufferSize);

got_value:
  // got the value in oInstallPath, check for ending '/' or '\'.
  int len = strlen(oInstallPath);
  if(len == 0) return false;
  if( oInstallPath[len-1] == '/' || oInstallPath[len-1] == '\\' )
    return true;
  if(len+1 >= (int)iBufferSize)
  {
    strncpy(oInstallPath, "", iBufferSize); //make empty if possible
    return false;
  }
  oInstallPath[len] = '\\';
  oInstallPath[len+1] = 0;
  return true;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * 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.
 */

// Determine coverage of font given its raw "cmap" OpenType table

#define LOG_TAG "Minikin"
#include <cutils/log.h>

#include <vector>
using std::vector;

#include <minikin/SparseBitSet.h>
#include <minikin/CmapCoverage.h>

namespace android {

// These could perhaps be optimized to use __builtin_bswap16 and friends.
static uint32_t readU16(const uint8_t* data, size_t offset) {
    return ((uint32_t)data[offset]) << 8 | ((uint32_t)data[offset + 1]);
}

static uint32_t readU32(const uint8_t* data, size_t offset) {
    return ((uint32_t)data[offset]) << 24 | ((uint32_t)data[offset + 1]) << 16 |
        ((uint32_t)data[offset + 2]) << 8 | ((uint32_t)data[offset + 3]);
}

static void addRange(vector<uint32_t> &coverage, uint32_t start, uint32_t end) {
#ifdef VERBOSE_DEBUG
    ALOGD("adding range %d-%d\n", start, end);
#endif
    if (coverage.empty() || coverage.back() < start) {
        coverage.push_back(start);
        coverage.push_back(end);
    } else {
        coverage.back() = end;
    }
}

// Get the coverage information out of a Format 4 subtable, storing it in the coverage vector
static bool getCoverageFormat4(vector<uint32_t>& coverage, const uint8_t* data, size_t size) {
    const size_t kSegCountOffset = 6;
    const size_t kEndCountOffset = 14;
    const size_t kHeaderSize = 16;
    const size_t kSegmentSize = 8;  // total size of array elements for one segment
    if (kEndCountOffset > size) {
        return false;
    }
    size_t segCount = readU16(data, kSegCountOffset) >> 1;
    if (kHeaderSize + segCount * kSegmentSize > size) {
        return false;
    }
    for (size_t i = 0; i < segCount; i++) {
        uint32_t end = readU16(data, kEndCountOffset + 2 * i);
        uint32_t start = readU16(data, kHeaderSize + 2 * (segCount + i));
        if (end < start) {
            // invalid segment range: size must be positive
            return false;
        }
        uint32_t rangeOffset = readU16(data, kHeaderSize + 2 * (3 * segCount + i));
        if (rangeOffset == 0) {
            uint32_t delta = readU16(data, kHeaderSize + 2 * (2 * segCount + i));
            if (((end + delta) & 0xffff) > end - start) {
                addRange(coverage, start, end + 1);
            } else {
                for (uint32_t j = start; j < end + 1; j++) {
                    if (((j + delta) & 0xffff) != 0) {
                        addRange(coverage, j, j + 1);
                    }
                }
            }
        } else {
            for (uint32_t j = start; j < end + 1; j++) {
                uint32_t actualRangeOffset = kHeaderSize + 6 * segCount + rangeOffset +
                    (i + j - start) * 2;
                if (actualRangeOffset + 2 > size) {
                    // invalid rangeOffset is considered a "warning" by OpenType Sanitizer
                    continue;
                }
                uint32_t glyphId = readU16(data, actualRangeOffset);
                if (glyphId != 0) {
                    addRange(coverage, j, j + 1);
                }
            }
        }
    }
    return true;
}

// Get the coverage information out of a Format 12 subtable, storing it in the coverage vector
static bool getCoverageFormat12(vector<uint32_t>& coverage, const uint8_t* data, size_t size) {
    const size_t kNGroupsOffset = 12;
    const size_t kFirstGroupOffset = 16;
    const size_t kGroupSize = 12;
    const size_t kStartCharCodeOffset = 0;
    const size_t kEndCharCodeOffset = 4;
    const size_t kMaxNGroups = 0xfffffff0 / kGroupSize;  // protection against overflow
    // For all values < kMaxNGroups, kFirstGroupOffset + nGroups * kGroupSize fits in 32 bits.
    if (kFirstGroupOffset > size) {
        return false;
    }
    uint32_t nGroups = readU32(data, kNGroupsOffset);
    if (nGroups >= kMaxNGroups || kFirstGroupOffset + nGroups * kGroupSize > size) {
        return false;
    }
    for (uint32_t i = 0; i < nGroups; i++) {
        uint32_t groupOffset = kFirstGroupOffset + i * kGroupSize;
        uint32_t start = readU32(data, groupOffset + kStartCharCodeOffset);
        uint32_t end = readU32(data, groupOffset + kEndCharCodeOffset);
        if (end < start) {
            // invalid group range: size must be positive
            return false;
        }
        addRange(coverage, start, end + 1);  // file is inclusive, vector is exclusive
    }
    return true;
}

bool CmapCoverage::getCoverage(SparseBitSet& coverage, const uint8_t* cmap_data, size_t cmap_size) {
    vector<uint32_t> coverageVec;
    const size_t kHeaderSize = 4;
    const size_t kNumTablesOffset = 2;
    const size_t kTableSize = 8;
    const size_t kPlatformIdOffset = 0;
    const size_t kEncodingIdOffset = 2;
    const size_t kOffsetOffset = 4;
    const uint16_t kMicrosoftPlatformId = 3;
    const uint16_t kUnicodeBmpEncodingId = 1;
    const uint16_t kUnicodeUcs4EncodingId = 10;
    const uint32_t kNoTable = UINT32_MAX;
    if (kHeaderSize > cmap_size) {
        return false;
    }
    uint32_t numTables = readU16(cmap_data, kNumTablesOffset);
    if (kHeaderSize + numTables * kTableSize > cmap_size) {
        return false;
    }
    uint32_t bestTable = kNoTable;
    for (uint32_t i = 0; i < numTables; i++) {
        uint16_t platformId = readU16(cmap_data, kHeaderSize + i * kTableSize + kPlatformIdOffset);
        uint16_t encodingId = readU16(cmap_data, kHeaderSize + i * kTableSize + kEncodingIdOffset);
        if (platformId == kMicrosoftPlatformId && encodingId == kUnicodeUcs4EncodingId) {
            bestTable = i;
            break;
        } else if (platformId == kMicrosoftPlatformId && encodingId == kUnicodeBmpEncodingId) {
            bestTable = i;
        }
    }
#ifdef VERBOSE_DEBUG
    ALOGD("best table = %d\n", bestTable);
#endif
    if (bestTable == kNoTable) {
        return false;
    }
    uint32_t offset = readU32(cmap_data, kHeaderSize + bestTable * kTableSize + kOffsetOffset);
    if (offset > cmap_size - 2) {
        return false;
    }
    uint16_t format = readU16(cmap_data, offset);
    bool success = false;
    const uint8_t* tableData = cmap_data + offset;
    const size_t tableSize = cmap_size - offset;
    if (format == 4) {
        success = getCoverageFormat4(coverageVec, tableData, tableSize);
    } else if (format == 12) {
        success = getCoverageFormat12(coverageVec, tableData, tableSize);
    }
    if (success) {
        coverage.initFromRanges(&coverageVec.front(), coverageVec.size() >> 1);
    }
#ifdef VERBOSE_DEBUG
    for (size_t i = 0; i < coverageVec.size(); i += 2) {
        ALOGD("%x:%x\n", coverageVec[i], coverageVec[i + 1]);
    }
    ALOGD("success = %d", success);
#endif
    return success;
}

}  // namespace android
<commit_msg>Add error logging on invalid cmap - DO NOT MERGE am: 48e5307447<commit_after>/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * 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.
 */

// Determine coverage of font given its raw "cmap" OpenType table

#define LOG_TAG "Minikin"
#include <cutils/log.h>

#define LOG_TAG "Minikin"
#include <cutils/log.h>

#include <vector>
using std::vector;

#include <minikin/SparseBitSet.h>
#include <minikin/CmapCoverage.h>

namespace android {

// These could perhaps be optimized to use __builtin_bswap16 and friends.
static uint32_t readU16(const uint8_t* data, size_t offset) {
    return ((uint32_t)data[offset]) << 8 | ((uint32_t)data[offset + 1]);
}

static uint32_t readU32(const uint8_t* data, size_t offset) {
    return ((uint32_t)data[offset]) << 24 | ((uint32_t)data[offset + 1]) << 16 |
        ((uint32_t)data[offset + 2]) << 8 | ((uint32_t)data[offset + 3]);
}

static void addRange(vector<uint32_t> &coverage, uint32_t start, uint32_t end) {
#ifdef VERBOSE_DEBUG
    ALOGD("adding range %d-%d\n", start, end);
#endif
    if (coverage.empty() || coverage.back() < start) {
        coverage.push_back(start);
        coverage.push_back(end);
    } else {
        coverage.back() = end;
    }
}

// Get the coverage information out of a Format 4 subtable, storing it in the coverage vector
static bool getCoverageFormat4(vector<uint32_t>& coverage, const uint8_t* data, size_t size) {
    const size_t kSegCountOffset = 6;
    const size_t kEndCountOffset = 14;
    const size_t kHeaderSize = 16;
    const size_t kSegmentSize = 8;  // total size of array elements for one segment
    if (kEndCountOffset > size) {
        return false;
    }
    size_t segCount = readU16(data, kSegCountOffset) >> 1;
    if (kHeaderSize + segCount * kSegmentSize > size) {
        return false;
    }
    for (size_t i = 0; i < segCount; i++) {
        uint32_t end = readU16(data, kEndCountOffset + 2 * i);
        uint32_t start = readU16(data, kHeaderSize + 2 * (segCount + i));
        if (end < start) {
            // invalid segment range: size must be positive
            android_errorWriteLog(0x534e4554, "26413177");
            return false;
        }
        uint32_t rangeOffset = readU16(data, kHeaderSize + 2 * (3 * segCount + i));
        if (rangeOffset == 0) {
            uint32_t delta = readU16(data, kHeaderSize + 2 * (2 * segCount + i));
            if (((end + delta) & 0xffff) > end - start) {
                addRange(coverage, start, end + 1);
            } else {
                for (uint32_t j = start; j < end + 1; j++) {
                    if (((j + delta) & 0xffff) != 0) {
                        addRange(coverage, j, j + 1);
                    }
                }
            }
        } else {
            for (uint32_t j = start; j < end + 1; j++) {
                uint32_t actualRangeOffset = kHeaderSize + 6 * segCount + rangeOffset +
                    (i + j - start) * 2;
                if (actualRangeOffset + 2 > size) {
                    // invalid rangeOffset is considered a "warning" by OpenType Sanitizer
                    continue;
                }
                uint32_t glyphId = readU16(data, actualRangeOffset);
                if (glyphId != 0) {
                    addRange(coverage, j, j + 1);
                }
            }
        }
    }
    return true;
}

// Get the coverage information out of a Format 12 subtable, storing it in the coverage vector
static bool getCoverageFormat12(vector<uint32_t>& coverage, const uint8_t* data, size_t size) {
    const size_t kNGroupsOffset = 12;
    const size_t kFirstGroupOffset = 16;
    const size_t kGroupSize = 12;
    const size_t kStartCharCodeOffset = 0;
    const size_t kEndCharCodeOffset = 4;
    const size_t kMaxNGroups = 0xfffffff0 / kGroupSize;  // protection against overflow
    // For all values < kMaxNGroups, kFirstGroupOffset + nGroups * kGroupSize fits in 32 bits.
    if (kFirstGroupOffset > size) {
        return false;
    }
    uint32_t nGroups = readU32(data, kNGroupsOffset);
    if (nGroups >= kMaxNGroups || kFirstGroupOffset + nGroups * kGroupSize > size) {
        android_errorWriteLog(0x534e4554, "25645298");
        return false;
    }
    for (uint32_t i = 0; i < nGroups; i++) {
        uint32_t groupOffset = kFirstGroupOffset + i * kGroupSize;
        uint32_t start = readU32(data, groupOffset + kStartCharCodeOffset);
        uint32_t end = readU32(data, groupOffset + kEndCharCodeOffset);
        if (end < start) {
            // invalid group range: size must be positive
            android_errorWriteLog(0x534e4554, "26413177");
            return false;
        }
        addRange(coverage, start, end + 1);  // file is inclusive, vector is exclusive
    }
    return true;
}

bool CmapCoverage::getCoverage(SparseBitSet& coverage, const uint8_t* cmap_data, size_t cmap_size) {
    vector<uint32_t> coverageVec;
    const size_t kHeaderSize = 4;
    const size_t kNumTablesOffset = 2;
    const size_t kTableSize = 8;
    const size_t kPlatformIdOffset = 0;
    const size_t kEncodingIdOffset = 2;
    const size_t kOffsetOffset = 4;
    const uint16_t kMicrosoftPlatformId = 3;
    const uint16_t kUnicodeBmpEncodingId = 1;
    const uint16_t kUnicodeUcs4EncodingId = 10;
    const uint32_t kNoTable = UINT32_MAX;
    if (kHeaderSize > cmap_size) {
        return false;
    }
    uint32_t numTables = readU16(cmap_data, kNumTablesOffset);
    if (kHeaderSize + numTables * kTableSize > cmap_size) {
        return false;
    }
    uint32_t bestTable = kNoTable;
    for (uint32_t i = 0; i < numTables; i++) {
        uint16_t platformId = readU16(cmap_data, kHeaderSize + i * kTableSize + kPlatformIdOffset);
        uint16_t encodingId = readU16(cmap_data, kHeaderSize + i * kTableSize + kEncodingIdOffset);
        if (platformId == kMicrosoftPlatformId && encodingId == kUnicodeUcs4EncodingId) {
            bestTable = i;
            break;
        } else if (platformId == kMicrosoftPlatformId && encodingId == kUnicodeBmpEncodingId) {
            bestTable = i;
        }
    }
#ifdef VERBOSE_DEBUG
    ALOGD("best table = %d\n", bestTable);
#endif
    if (bestTable == kNoTable) {
        return false;
    }
    uint32_t offset = readU32(cmap_data, kHeaderSize + bestTable * kTableSize + kOffsetOffset);
    if (offset > cmap_size - 2) {
        return false;
    }
    uint16_t format = readU16(cmap_data, offset);
    bool success = false;
    const uint8_t* tableData = cmap_data + offset;
    const size_t tableSize = cmap_size - offset;
    if (format == 4) {
        success = getCoverageFormat4(coverageVec, tableData, tableSize);
    } else if (format == 12) {
        success = getCoverageFormat12(coverageVec, tableData, tableSize);
    }
    if (success) {
        coverage.initFromRanges(&coverageVec.front(), coverageVec.size() >> 1);
    }
#ifdef VERBOSE_DEBUG
    for (size_t i = 0; i < coverageVec.size(); i += 2) {
        ALOGD("%x:%x\n", coverageVec[i], coverageVec[i + 1]);
    }
    ALOGD("success = %d", success);
#endif
    return success;
}

}  // namespace android
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * 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 <stddef.h>
#include <string.h>
#include <minikin/SparseBitSet.h>

namespace android {

const uint32_t SparseBitSet::kNotFound;

void SparseBitSet::clear() {
    mMaxVal = 0;
    mIndices.reset();
    mBitmaps.reset();
}

uint32_t SparseBitSet::calcNumPages(const uint32_t* ranges, size_t nRanges) {
    bool haveZeroPage = false;
    uint32_t nonzeroPageEnd = 0;
    uint32_t nPages = 0;
    for (size_t i = 0; i < nRanges; i++) {
        uint32_t start = ranges[i * 2];
        uint32_t end = ranges[i * 2 + 1];
        uint32_t startPage = start >> kLogValuesPerPage;
        uint32_t endPage = (end - 1) >> kLogValuesPerPage;
        if (startPage >= nonzeroPageEnd) {
            if (startPage > nonzeroPageEnd) {
                if (!haveZeroPage) {
                    haveZeroPage = true;
                    nPages++;
                }
            }
            nPages++;
        }
        nPages += endPage - startPage;
        nonzeroPageEnd = endPage + 1;
    }
    return nPages;
}

void SparseBitSet::initFromRanges(const uint32_t* ranges, size_t nRanges) {
    if (nRanges == 0) {
        mMaxVal = 0;
        mIndices.reset();
        mBitmaps.reset();
        return;
    }
    mMaxVal = ranges[nRanges * 2 - 1];
    size_t indexSize = (mMaxVal + kPageMask) >> kLogValuesPerPage;
    mIndices.reset(new uint32_t[indexSize]);
    uint32_t nPages = calcNumPages(ranges, nRanges);
    mBitmaps.reset(new element[nPages << (kLogValuesPerPage - kLogBitsPerEl)]);
    memset(mBitmaps.get(), 0, nPages << (kLogValuesPerPage - 3));
    mZeroPageIndex = noZeroPage;
    uint32_t nonzeroPageEnd = 0;
    uint32_t currentPage = 0;
    for (size_t i = 0; i < nRanges; i++) {
        uint32_t start = ranges[i * 2];
        uint32_t end = ranges[i * 2 + 1];
        uint32_t startPage = start >> kLogValuesPerPage;
        uint32_t endPage = (end - 1) >> kLogValuesPerPage;
        if (startPage >= nonzeroPageEnd) {
            if (startPage > nonzeroPageEnd) {
                if (mZeroPageIndex == noZeroPage) {
                    mZeroPageIndex = (currentPage++) << (kLogValuesPerPage - kLogBitsPerEl);
                }
                for (uint32_t j = nonzeroPageEnd; j < startPage; j++) {
                    mIndices[j] = mZeroPageIndex;
                }
            }
            mIndices[startPage] = (currentPage++) << (kLogValuesPerPage - kLogBitsPerEl);
        }

        size_t index = ((currentPage - 1) << (kLogValuesPerPage - kLogBitsPerEl)) +
            ((start & kPageMask) >> kLogBitsPerEl);
        size_t nElements = (end - (start & ~kElMask) + kElMask) >> kLogBitsPerEl;
        if (nElements == 1) {
            mBitmaps[index] |= (kElAllOnes >> (start & kElMask)) &
                (kElAllOnes << ((-end) & kElMask));
        } else {
            mBitmaps[index] |= kElAllOnes >> (start & kElMask);
            for (size_t j = 1; j < nElements - 1; j++) {
                mBitmaps[index + j] = kElAllOnes;
            }
            mBitmaps[index + nElements - 1] |= kElAllOnes << ((-end) & kElMask);
        }
        for (size_t j = startPage + 1; j < endPage + 1; j++) {
            mIndices[j] = (currentPage++) << (kLogValuesPerPage - kLogBitsPerEl);
        }
        nonzeroPageEnd = endPage + 1;
    }
}

// Note: this implementation depends on GCC builtin, and also assumes 32-bit elements.
int SparseBitSet::CountLeadingZeros(element x) {
    return __builtin_clz(x);
}

uint32_t SparseBitSet::nextSetBit(uint32_t fromIndex) const {
    if (fromIndex >= mMaxVal) {
        return kNotFound;
    }
    uint32_t fromPage = fromIndex >> kLogValuesPerPage;
    const element* bitmap = &mBitmaps[mIndices[fromPage]];
    uint32_t offset = (fromIndex & kPageMask) >> kLogBitsPerEl;
    element e = bitmap[offset] & (kElAllOnes >> (fromIndex & kElMask));
    if (e != 0) {
        return (fromIndex & ~kElMask) + CountLeadingZeros(e);
    }
    for (uint32_t j = offset + 1; j < (1 << (kLogValuesPerPage - kLogBitsPerEl)); j++) {
        e = bitmap[j];
        if (e != 0) {
            return (fromIndex & ~kPageMask) + (j << kLogBitsPerEl) + CountLeadingZeros(e);
        }
    }
    uint32_t maxPage = (mMaxVal + kPageMask) >> kLogValuesPerPage;
    for (uint32_t page = fromPage + 1; page < maxPage; page++) {
        uint32_t index = mIndices[page];
        if (index == mZeroPageIndex) {
            continue;
        }
        bitmap = &mBitmaps[index];
        for (uint32_t j = 0; j < (1 << (kLogValuesPerPage - kLogBitsPerEl)); j++) {
            e = bitmap[j];
            if (e != 0) {
                return (page << kLogValuesPerPage) + (j << kLogBitsPerEl) + CountLeadingZeros(e);
            }
        }
    }
    return kNotFound;
}

}  // namespace android
<commit_msg>Use __builtin_clzl if element is long<commit_after>/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * 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 <stddef.h>
#include <string.h>
#include <minikin/SparseBitSet.h>

namespace android {

const uint32_t SparseBitSet::kNotFound;

void SparseBitSet::clear() {
    mMaxVal = 0;
    mIndices.reset();
    mBitmaps.reset();
}

uint32_t SparseBitSet::calcNumPages(const uint32_t* ranges, size_t nRanges) {
    bool haveZeroPage = false;
    uint32_t nonzeroPageEnd = 0;
    uint32_t nPages = 0;
    for (size_t i = 0; i < nRanges; i++) {
        uint32_t start = ranges[i * 2];
        uint32_t end = ranges[i * 2 + 1];
        uint32_t startPage = start >> kLogValuesPerPage;
        uint32_t endPage = (end - 1) >> kLogValuesPerPage;
        if (startPage >= nonzeroPageEnd) {
            if (startPage > nonzeroPageEnd) {
                if (!haveZeroPage) {
                    haveZeroPage = true;
                    nPages++;
                }
            }
            nPages++;
        }
        nPages += endPage - startPage;
        nonzeroPageEnd = endPage + 1;
    }
    return nPages;
}

void SparseBitSet::initFromRanges(const uint32_t* ranges, size_t nRanges) {
    if (nRanges == 0) {
        mMaxVal = 0;
        mIndices.reset();
        mBitmaps.reset();
        return;
    }
    mMaxVal = ranges[nRanges * 2 - 1];
    size_t indexSize = (mMaxVal + kPageMask) >> kLogValuesPerPage;
    mIndices.reset(new uint32_t[indexSize]);
    uint32_t nPages = calcNumPages(ranges, nRanges);
    mBitmaps.reset(new element[nPages << (kLogValuesPerPage - kLogBitsPerEl)]);
    memset(mBitmaps.get(), 0, nPages << (kLogValuesPerPage - 3));
    mZeroPageIndex = noZeroPage;
    uint32_t nonzeroPageEnd = 0;
    uint32_t currentPage = 0;
    for (size_t i = 0; i < nRanges; i++) {
        uint32_t start = ranges[i * 2];
        uint32_t end = ranges[i * 2 + 1];
        uint32_t startPage = start >> kLogValuesPerPage;
        uint32_t endPage = (end - 1) >> kLogValuesPerPage;
        if (startPage >= nonzeroPageEnd) {
            if (startPage > nonzeroPageEnd) {
                if (mZeroPageIndex == noZeroPage) {
                    mZeroPageIndex = (currentPage++) << (kLogValuesPerPage - kLogBitsPerEl);
                }
                for (uint32_t j = nonzeroPageEnd; j < startPage; j++) {
                    mIndices[j] = mZeroPageIndex;
                }
            }
            mIndices[startPage] = (currentPage++) << (kLogValuesPerPage - kLogBitsPerEl);
        }

        size_t index = ((currentPage - 1) << (kLogValuesPerPage - kLogBitsPerEl)) +
            ((start & kPageMask) >> kLogBitsPerEl);
        size_t nElements = (end - (start & ~kElMask) + kElMask) >> kLogBitsPerEl;
        if (nElements == 1) {
            mBitmaps[index] |= (kElAllOnes >> (start & kElMask)) &
                (kElAllOnes << ((-end) & kElMask));
        } else {
            mBitmaps[index] |= kElAllOnes >> (start & kElMask);
            for (size_t j = 1; j < nElements - 1; j++) {
                mBitmaps[index + j] = kElAllOnes;
            }
            mBitmaps[index + nElements - 1] |= kElAllOnes << ((-end) & kElMask);
        }
        for (size_t j = startPage + 1; j < endPage + 1; j++) {
            mIndices[j] = (currentPage++) << (kLogValuesPerPage - kLogBitsPerEl);
        }
        nonzeroPageEnd = endPage + 1;
    }
}

int SparseBitSet::CountLeadingZeros(element x) {
    // Note: GCC / clang builtin
    return sizeof(element) <= sizeof(int) ? __builtin_clz(x) : __builtin_clzl(x);
}

uint32_t SparseBitSet::nextSetBit(uint32_t fromIndex) const {
    if (fromIndex >= mMaxVal) {
        return kNotFound;
    }
    uint32_t fromPage = fromIndex >> kLogValuesPerPage;
    const element* bitmap = &mBitmaps[mIndices[fromPage]];
    uint32_t offset = (fromIndex & kPageMask) >> kLogBitsPerEl;
    element e = bitmap[offset] & (kElAllOnes >> (fromIndex & kElMask));
    if (e != 0) {
        return (fromIndex & ~kElMask) + CountLeadingZeros(e);
    }
    for (uint32_t j = offset + 1; j < (1 << (kLogValuesPerPage - kLogBitsPerEl)); j++) {
        e = bitmap[j];
        if (e != 0) {
            return (fromIndex & ~kPageMask) + (j << kLogBitsPerEl) + CountLeadingZeros(e);
        }
    }
    uint32_t maxPage = (mMaxVal + kPageMask) >> kLogValuesPerPage;
    for (uint32_t page = fromPage + 1; page < maxPage; page++) {
        uint32_t index = mIndices[page];
        if (index == mZeroPageIndex) {
            continue;
        }
        bitmap = &mBitmaps[index];
        for (uint32_t j = 0; j < (1 << (kLogValuesPerPage - kLogBitsPerEl)); j++) {
            e = bitmap[j];
            if (e != 0) {
                return (page << kLogValuesPerPage) + (j << kLogBitsPerEl) + CountLeadingZeros(e);
            }
        }
    }
    return kNotFound;
}

}  // namespace android
<|endoftext|>


<commit_before>// LICENSE/*{{{*/
/*
  sxc - Simple Xmpp Client
  Copyright (C) 2008 Dennis Felsing, Andreas Waidler

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU 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 General Public License for more details.

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

/* $Id$ */

// INCLUDES/*{{{*/

#include <string>
#include <fstream>
#include <pthread.h>
#include <signal.h>

#include <errno.h>
#include <sstream>
#include <sys/stat.h>
#include <File/InputBase.hxx>
#include <Exception/FileInputException.hxx>
#include <Exception/Errno.hxx>
#include <Exception/Type.hxx>

/*}}}*/

File::InputBase::InputBase()/*{{{*/
: _isFifoValid(false),
  _isLocked(false),
  _isThreadRunning(false)
{
}

/*}}}*/
File::InputBase::~InputBase()/*{{{*/
{
    close();
}

/*}}}*/
void File::InputBase::initialize()/*{{{*/
{
    // Initialize the path where the FIFO should be located.
    _path = _createPath();
}

/*}}}*/
void File::InputBase::open(bool createIfMissing)/*{{{*/
{
    if (_fifo.is_open)
        return;

    try {
        validate();
    } catch (Exception::FileInputException e) {
        // validate() failed. If createIfMissing is true, check whether it was
        // because the file is missing.
        if (false == createIfMissing || Exception::FileMissing != e.getType())
            throw e;
        create();
    }

    _fifo.open(_path.c_str());
    if (!_fifo.is_open())
        throw Exception::FileInputException(Exception::OpenFailed, "unexpected");
}

/*}}}*/
void File::InputBase::listen(bool blocking)/*{{{*/
{
    // Do not start to listen if the FIFO is currently locked. Otherwise we
    // could end up handling the input twice.
    if (_isLocked) {
        std::string message = _path + " already locked.";
        throw Exception::FileInputException(Exception::FileLocked, message);
        return;
    }

    _isLocked = true;
    // Start the thread in the background.
    pthread_create(&_thread, NULL, _listen, this);
    // Join the thread when this functions should read in a blocking way.
    if (true == blocking)
        pthread_join(_thread, NULL);
}

/*}}}*/
void File::InputBase::_read()/*{{{*/
{
    // Refuse to read from an invalid FIFO.
    if (!_isFifoValid) {
        throw Exception::FileInputException(Exception::BadFile, "Refusing to read.");
    }

    // Gets filled with everything that is written until the other end closes
    // the pipe.
    std::string input;
    // Input is read line by line and put in buffer.
    std::string buffer;
    while (getline(_fifo, buffer)) {
        input += buffer;
    }
    _handleInput(input);
}

/*}}}*/
void File::InputBase::close()/*{{{*/
{
    if (_isThreadRunning) {
        pthread_kill(_thread, SIGINT);
        _isThreadRunning = false;
    }
    if (_fifo.is_open()) {
        _fifo.close();
    }
    if (_isLocked) {
        _isLocked = false;
    }
}

/*}}}*/
void File::InputBase::create()/*{{{*/
{
    // Try to create FIFO with chmod 600.
    if (0 == mkfifo(_path.c_str(), S_IRUSR | S_IWUSR))
        return;

    // Creation of FIFO failed.
    Exception::Type type = Exception::errnoToType(errno);
    std::string message  = "Could not create FIFO " + _path;
    throw Exception::FileInputException(type, message);
}

/*}}}*/
void File::InputBase::validate()/*{{{*/
{
    // Try to get file stats, needed for analyzing the chmod of the file.
    struct stat fstat;
    if (0 != stat(_path.c_str(), &fstat)) {
        Exception::Type type = Exception::errnoToType(errno);
        std::string message  = "Could not get FIFO fstat: " + _path;
        throw Exception::FileInputException(type, message);
    }

    // Is this really a FIFO?
    if (!S_ISFIFO(fstat.st_mode)) {
        std::string message  = "Not a FIFO: " + _path;
        throw Exception::FileInputException(Exception::BadFile, message);
    }

    // Check for chmod 600:
    if (0 == fstat.st_mode & S_IRUSR
    || 0 == fstat.st_mode & S_IWUSR
    || 0 != fstat.st_mode & S_IRGRP
    || 0 != fstat.st_mode & S_IWGRP
    || 0 != fstat.st_mode & S_IROTH
    || 0 != fstat.st_mode & S_IWOTH) {
        // Converts __mode_t st_mode to human-readable string (octal notation):
        std::stringstream mode;
        mode << std::oct << fstat.st_mode;
        // Extract only necessary part (user, group, other) from file mode:
        std::string message = _path + ": Chmod should be 600, found "
                            + mode.str().substr(2);
        throw Exception::FileInputException(Exception::BadFile, message);
    }

    _isFifoValid = true;
}

/*}}}*/
void *File::InputBase::_listen(void *fifo)/*{{{*/
{
    InputBase *that = (InputBase *) fifo;
    that->_isThreadRunning = true;
    do {
        // _read() reads blocking until the other end closes the pipe. This
        // loop will always restart _read() after it handled some input and
        // returned.
        that->_read();
    } while (true);

    return NULL;
}

/*}}}*/

// Use no tabs at all; four spaces indentation; max. eighty chars per line.
// vim: et ts=4 sw=4 tw=80 fo+=c fdm=marker

<commit_msg>InputBase::listen(): Added call to open().<commit_after>// LICENSE/*{{{*/
/*
  sxc - Simple Xmpp Client
  Copyright (C) 2008 Dennis Felsing, Andreas Waidler

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU 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 General Public License for more details.

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

/* $Id$ */

// INCLUDES/*{{{*/

#include <string>
#include <fstream>
#include <pthread.h>
#include <signal.h>

#include <errno.h>
#include <sstream>
#include <sys/stat.h>
#include <File/InputBase.hxx>
#include <Exception/FileInputException.hxx>
#include <Exception/Errno.hxx>
#include <Exception/Type.hxx>

/*}}}*/

File::InputBase::InputBase()/*{{{*/
: _isFifoValid(false),
  _isLocked(false),
  _isThreadRunning(false)
{
}

/*}}}*/
File::InputBase::~InputBase()/*{{{*/
{
    close();
}

/*}}}*/
void File::InputBase::initialize()/*{{{*/
{
    // Initialize the path where the FIFO should be located.
    _path = _createPath();
}

/*}}}*/
void File::InputBase::open(bool createIfMissing)/*{{{*/
{
    if (_fifo.is_open())
        return;

    try {
        validate();
    } catch (Exception::FileInputException e) {
        // validate() failed. If createIfMissing is true, check whether it was
        // because the file is missing.
        if (false == createIfMissing || Exception::FileMissing != e.getType())
            throw e;
        create();
    }

    _fifo.open(_path.c_str());
    if (!_fifo.is_open())
        throw Exception::FileInputException(Exception::OpenFailed, "unexpected");
}

/*}}}*/
void File::InputBase::listen(bool blocking)/*{{{*/
{
    // Do not start to listen if the FIFO is currently locked. Otherwise we
    // could end up handling the input twice.
    if (_isLocked) {
        std::string message = _path + " already locked.";
        throw Exception::FileInputException(Exception::FileLocked, message);
        return;
    }
    _isLocked = true;

    open();

    // Start the thread in the background.
    pthread_create(&_thread, NULL, _listen, this);
    // Join the thread when this functions should read in a blocking way.
    if (true == blocking)
        pthread_join(_thread, NULL);
}

/*}}}*/
void File::InputBase::_read()/*{{{*/
{
    // Refuse to read from an invalid FIFO.
    if (!_isFifoValid) {
        throw Exception::FileInputException(Exception::BadFile, "Refusing to read.");
    }

    // Gets filled with everything that is written until the other end closes
    // the pipe.
    std::string input;
    // Input is read line by line and put in buffer.
    std::string buffer;
    while (getline(_fifo, buffer)) {
        input += buffer;
    }
    _handleInput(input);
}

/*}}}*/
void File::InputBase::close()/*{{{*/
{
    if (_isThreadRunning) {
        pthread_kill(_thread, SIGINT);
        _isThreadRunning = false;
    }
    if (_fifo.is_open()) {
        _fifo.close();
    }
    if (_isLocked) {
        _isLocked = false;
    }
}

/*}}}*/
void File::InputBase::create()/*{{{*/
{
    // Try to create FIFO with chmod 600.
    if (0 == mkfifo(_path.c_str(), S_IRUSR | S_IWUSR))
        return;

    // Creation of FIFO failed.
    Exception::Type type = Exception::errnoToType(errno);
    std::string message  = "Could not create FIFO " + _path;
    throw Exception::FileInputException(type, message);
}

/*}}}*/
void File::InputBase::validate()/*{{{*/
{
    // Try to get file stats, needed for analyzing the chmod of the file.
    struct stat fstat;
    if (0 != stat(_path.c_str(), &fstat)) {
        Exception::Type type = Exception::errnoToType(errno);
        std::string message  = "Could not get FIFO fstat: " + _path;
        throw Exception::FileInputException(type, message);
    }

    // Is this really a FIFO?
    if (!S_ISFIFO(fstat.st_mode)) {
        std::string message  = "Not a FIFO: " + _path;
        throw Exception::FileInputException(Exception::BadFile, message);
    }

    // Check for chmod 600:
    if (0 == fstat.st_mode & S_IRUSR
    || 0 == fstat.st_mode & S_IWUSR
    || 0 != fstat.st_mode & S_IRGRP
    || 0 != fstat.st_mode & S_IWGRP
    || 0 != fstat.st_mode & S_IROTH
    || 0 != fstat.st_mode & S_IWOTH) {
        // Converts __mode_t st_mode to human-readable string (octal notation):
        std::stringstream mode;
        mode << std::oct << fstat.st_mode;
        // Extract only necessary part (user, group, other) from file mode:
        std::string message = _path + ": Chmod should be 600, found "
                            + mode.str().substr(2);
        throw Exception::FileInputException(Exception::BadFile, message);
    }

    _isFifoValid = true;
}

/*}}}*/
void *File::InputBase::_listen(void *fifo)/*{{{*/
{
    InputBase *that = (InputBase *) fifo;
    that->_isThreadRunning = true;
    do {
        // _read() reads blocking until the other end closes the pipe. This
        // loop will always restart _read() after it handled some input and
        // returned.
        that->_read();
    } while (true);

    return NULL;
}

/*}}}*/

// Use no tabs at all; four spaces indentation; max. eighty chars per line.
// vim: et ts=4 sw=4 tw=80 fo+=c fdm=marker

<|endoftext|>


<commit_before>//
// This file is part of the Marble Desktop Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2006-2007 Torsten Rahn <tackat@kde.org>"
// Copyright 2007      Inge Wallin  <ingwa@kde.org>"
//

// #include <zlib.h>

#include <QFile>
#include <QStringList>
#include <QApplication>
#include <QDebug>

QString escapeXml( const QString &str )
{
    QString xml = str;
    xml.replace("&", "&");
    xml.replace("<", "<");
    xml.replace(">", ">");
    xml.replace("'", "'");
    xml.replace("\"", """);

    return xml;
}

int main(int argc, char *argv[])
{
    QString  sourcefilename;
    QString  targetfilename;

    QApplication  app( argc, argv );

    for ( int i = 1; i < argc; ++i ) {
        if ( strcmp( argv[ i ], "-o" ) != 0 )
            continue;

        targetfilename = QString(argv[i+1]);
        sourcefilename = QString(argv[i+2]);

        qDebug() << "Source: " << sourcefilename;
        qDebug() << "Target: " << targetfilename;

        QFile  sourcefile( sourcefilename );
        sourcefile.open( QIODevice::ReadOnly );

        // Read the data serialized from the file.
        QTextStream  sourcestream( &sourcefile );
        sourcestream.setCodec("UTF-8");

        QFile  targetfile( targetfilename );
        targetfile.open( QIODevice::ReadWrite );

        QTextStream  targetstream( &targetfile );
        targetstream.setCodec("UTF-8");

        // gzFile gzDoc = gzopen( targetfilename.toLatin1(), "w");
        // QTextStream targetstream( new QString() );

        targetstream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?> \n"
                     << "<kml xmlns=\"http://earth.google.com/kml/2.0\"> \n"
                     << "<Document> \n";

        targetstream << "    <SimpleField> \n"
                     << "        <name>pop</name> \n"
                     << "        <type>int</type> \n"
                     << "    </SimpleField> \n";

        targetstream << "    <SimpleField> \n"
                     << "        <name>state</name> \n"
                     << "        <type>string</type> \n"
                     << "    </SimpleField> \n";

        targetstream << "    <SimpleField> \n"
                     << "        <name>CountryNameCode</name> \n"
                     << "        <type>string</type> \n"
                     << "    </SimpleField> \n";

        targetstream << "    <SimpleField> \n"
                     << "        <name>role</name> \n"
                     << "        <type>string</type> \n"
                     << "    </SimpleField> \n";

        targetstream << "\n";

        QString  rawline;
        QString  name;
        QString  state;
        QString  country;
        QString  role;
        QString  popstring;
        QString  latstring;
        QString  lngstring;
        float    lat;
        float    lng;
        int          population;
        QStringList  splitline;

        while ( !sourcestream.atEnd() ) {

            rawline=sourcestream.readLine();
            splitline = rawline.split("\t");

            name    = splitline[0];
            state   = splitline[1];
            country = splitline[2];
            role    = splitline[3];

            popstring = splitline[4];
            latstring = splitline[5];
            lngstring = splitline[6];

            population = (int) ( 1000 * popstring.toFloat() );

            lng = lngstring.left( lngstring.size() - 2 ).toFloat();
            if ( lngstring.contains( "W" ) )
                lng=-lng;

            lat = latstring.left( latstring.size() - 2 ).toFloat();
            if ( latstring.contains( "S" ) )
                lat=-lat;

            targetstream << "    <Placemark> \n";
            targetstream << "        <name>" << escapeXml( name ) << "</name> \n";
            targetstream << "        <state>" << escapeXml( state ) << "</state> \n";
            targetstream << "        <Country>\n"
                         << "	     <CountryNameCode>" << escapeXml( country.toUpper() ) << "</CountryNameCode>\n"
                         << "        </Country> \n";
            targetstream << "        <role>" << escapeXml( role ) << "</role> \n";
            targetstream << "        <pop>"
                         << escapeXml( QString::number( population ) ) << "</pop> \n";
            targetstream << "        <Point>\n"
                         << "            <coordinates>"
                         << escapeXml( QString::number( lng ) )
                         << ","
                         << escapeXml( QString::number( lat ) )
                         << "</coordinates> \n"
                         << "        </Point> \n";
            targetstream << "    </Placemark> \n";
        }

        targetstream << "</Document> \n"
                     << "</kml> \n";
        qDebug("Putting");

        // gzputs( gzDoc, targetstream.readAll().toUtf8() );
        // gzclose( gzDoc );

        sourcefile.close();
        targetfile.close();

        qDebug("Finished!");
        return 0;
    }

    qDebug(" asc2kml -o targetfile sourcefile");
    app.exit();
}
<commit_msg>Fix include<commit_after>//
// This file is part of the Marble Desktop Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2006-2007 Torsten Rahn <tackat@kde.org>"
// Copyright 2007      Inge Wallin  <ingwa@kde.org>"
//

// #include <zlib.h>

#include <QFile>
#include <QApplication>
#include <QDebug>

QString escapeXml( const QString &str )
{
    QString xml = str;
    xml.replace("&", "&");
    xml.replace("<", "<");
    xml.replace(">", ">");
    xml.replace("'", "'");
    xml.replace("\"", """);

    return xml;
}

int main(int argc, char *argv[])
{
    QString  sourcefilename;
    QString  targetfilename;

    QApplication  app( argc, argv );

    for ( int i = 1; i < argc; ++i ) {
        if ( strcmp( argv[ i ], "-o" ) != 0 )
            continue;

        targetfilename = QString(argv[i+1]);
        sourcefilename = QString(argv[i+2]);

        qDebug() << "Source: " << sourcefilename;
        qDebug() << "Target: " << targetfilename;

        QFile  sourcefile( sourcefilename );
        sourcefile.open( QIODevice::ReadOnly );

        // Read the data serialized from the file.
        QTextStream  sourcestream( &sourcefile );
        sourcestream.setCodec("UTF-8");

        QFile  targetfile( targetfilename );
        targetfile.open( QIODevice::ReadWrite );

        QTextStream  targetstream( &targetfile );
        targetstream.setCodec("UTF-8");

        // gzFile gzDoc = gzopen( targetfilename.toLatin1(), "w");
        // QTextStream targetstream( new QString() );

        targetstream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?> \n"
                     << "<kml xmlns=\"http://earth.google.com/kml/2.0\"> \n"
                     << "<Document> \n";

        targetstream << "    <SimpleField> \n"
                     << "        <name>pop</name> \n"
                     << "        <type>int</type> \n"
                     << "    </SimpleField> \n";

        targetstream << "    <SimpleField> \n"
                     << "        <name>state</name> \n"
                     << "        <type>string</type> \n"
                     << "    </SimpleField> \n";

        targetstream << "    <SimpleField> \n"
                     << "        <name>CountryNameCode</name> \n"
                     << "        <type>string</type> \n"
                     << "    </SimpleField> \n";

        targetstream << "    <SimpleField> \n"
                     << "        <name>role</name> \n"
                     << "        <type>string</type> \n"
                     << "    </SimpleField> \n";

        targetstream << "\n";

        QString  rawline;
        QString  name;
        QString  state;
        QString  country;
        QString  role;
        QString  popstring;
        QString  latstring;
        QString  lngstring;
        float    lat;
        float    lng;
        int          population;
        QStringList  splitline;

        while ( !sourcestream.atEnd() ) {

            rawline=sourcestream.readLine();
            splitline = rawline.split("\t");

            name    = splitline[0];
            state   = splitline[1];
            country = splitline[2];
            role    = splitline[3];

            popstring = splitline[4];
            latstring = splitline[5];
            lngstring = splitline[6];

            population = (int) ( 1000 * popstring.toFloat() );

            lng = lngstring.left( lngstring.size() - 2 ).toFloat();
            if ( lngstring.contains( "W" ) )
                lng=-lng;

            lat = latstring.left( latstring.size() - 2 ).toFloat();
            if ( latstring.contains( "S" ) )
                lat=-lat;

            targetstream << "    <Placemark> \n";
            targetstream << "        <name>" << escapeXml( name ) << "</name> \n";
            targetstream << "        <state>" << escapeXml( state ) << "</state> \n";
            targetstream << "        <Country>\n"
                         << "	     <CountryNameCode>" << escapeXml( country.toUpper() ) << "</CountryNameCode>\n"
                         << "        </Country> \n";
            targetstream << "        <role>" << escapeXml( role ) << "</role> \n";
            targetstream << "        <pop>"
                         << escapeXml( QString::number( population ) ) << "</pop> \n";
            targetstream << "        <Point>\n"
                         << "            <coordinates>"
                         << escapeXml( QString::number( lng ) )
                         << ","
                         << escapeXml( QString::number( lat ) )
                         << "</coordinates> \n"
                         << "        </Point> \n";
            targetstream << "    </Placemark> \n";
        }

        targetstream << "</Document> \n"
                     << "</kml> \n";
        qDebug("Putting");

        // gzputs( gzDoc, targetstream.readAll().toUtf8() );
        // gzclose( gzDoc );

        sourcefile.close();
        targetfile.close();

        qDebug("Finished!");
        return 0;
    }

    qDebug(" asc2kml -o targetfile sourcefile");
    app.exit();
}
<|endoftext|>


<commit_before>/***************************************************************************
    copyright            : (C) 2002 - 2008 by Scott Wheeler
    email                : wheeler@kde.org
 ***************************************************************************/

/***************************************************************************
 *   This library is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Lesser General Public License version   *
 *   2.1 as published by the Free Software Foundation.                     *
 *                                                                         *
 *   This library is distributed in the hope that it will be useful, but   *
 *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
 *   Lesser General Public License for more details.                       *
 *                                                                         *
 *   You should have received a copy of the GNU Lesser General Public      *
 *   License along with this library; if not, write to the Free Software   *
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA         *
 *   02110-1301  USA                                                       *
 *                                                                         *
 *   Alternatively, this file is available under the Mozilla Public        *
 *   License Version 1.1.  You may obtain a copy of the License at         *
 *   http://www.mozilla.org/MPL/                                           *
 ***************************************************************************/

#include <tbytevector.h>
#include <tdebug.h>

#include <flacpicture.h>
#include <xiphcomment.h>
#include <tpropertymap.h>

using namespace TagLib;

typedef List<FLAC::Picture *> PictureList;

class Ogg::XiphComment::XiphCommentPrivate
{
public:
  FieldListMap fieldListMap;
  String vendorID;
  String commentField;
  PictureList pictureList;
};

////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////

Ogg::XiphComment::XiphComment() : TagLib::Tag()
{
  d = new XiphCommentPrivate;
}

Ogg::XiphComment::XiphComment(const ByteVector &data) : TagLib::Tag()
{
  d = new XiphCommentPrivate;
  parse(data);
}

Ogg::XiphComment::~XiphComment()
{
  removePictures();
  delete d;
}

String Ogg::XiphComment::title() const
{
  if(d->fieldListMap["TITLE"].isEmpty())
    return String::null;
  return d->fieldListMap["TITLE"].toString();
}

String Ogg::XiphComment::artist() const
{
  if(d->fieldListMap["ARTIST"].isEmpty())
    return String::null;
  return d->fieldListMap["ARTIST"].toString();
}

String Ogg::XiphComment::album() const
{
  if(d->fieldListMap["ALBUM"].isEmpty())
    return String::null;
  return d->fieldListMap["ALBUM"].toString();
}

String Ogg::XiphComment::comment() const
{
  if(!d->fieldListMap["DESCRIPTION"].isEmpty()) {
    d->commentField = "DESCRIPTION";
    return d->fieldListMap["DESCRIPTION"].toString();
  }

  if(!d->fieldListMap["COMMENT"].isEmpty()) {
    d->commentField = "COMMENT";
    return d->fieldListMap["COMMENT"].toString();
  }

  return String::null;
}

String Ogg::XiphComment::genre() const
{
  if(d->fieldListMap["GENRE"].isEmpty())
    return String::null;
  return d->fieldListMap["GENRE"].toString();
}

TagLib::uint Ogg::XiphComment::year() const
{
  if(!d->fieldListMap["DATE"].isEmpty())
    return d->fieldListMap["DATE"].front().toInt();
  if(!d->fieldListMap["YEAR"].isEmpty())
    return d->fieldListMap["YEAR"].front().toInt();
  return 0;
}

TagLib::uint Ogg::XiphComment::track() const
{
  if(!d->fieldListMap["TRACKNUMBER"].isEmpty())
    return d->fieldListMap["TRACKNUMBER"].front().toInt();
  if(!d->fieldListMap["TRACKNUM"].isEmpty())
    return d->fieldListMap["TRACKNUM"].front().toInt();
  return 0;
}

void Ogg::XiphComment::setTitle(const String &s)
{
  addField("TITLE", s);
}

void Ogg::XiphComment::setArtist(const String &s)
{
  addField("ARTIST", s);
}

void Ogg::XiphComment::setAlbum(const String &s)
{
  addField("ALBUM", s);
}

void Ogg::XiphComment::setComment(const String &s)
{
  addField(d->commentField.isEmpty() ? "DESCRIPTION" : d->commentField, s);
}

void Ogg::XiphComment::setGenre(const String &s)
{
  addField("GENRE", s);
}

void Ogg::XiphComment::setYear(uint i)
{
  removeField("YEAR");
  if(i == 0)
    removeField("DATE");
  else
    addField("DATE", String::number(i));
}

void Ogg::XiphComment::setTrack(uint i)
{
  removeField("TRACKNUM");
  if(i == 0)
    removeField("TRACKNUMBER");
  else
    addField("TRACKNUMBER", String::number(i));
}

bool Ogg::XiphComment::isEmpty() const
{
  FieldListMap::ConstIterator it = d->fieldListMap.begin();
  for(; it != d->fieldListMap.end(); ++it)
    if(!(*it).second.isEmpty())
      return false;

  return true;
}

TagLib::uint Ogg::XiphComment::fieldCount() const
{
  uint count = 0;

  FieldListMap::ConstIterator it = d->fieldListMap.begin();
  for(; it != d->fieldListMap.end(); ++it)
    count += (*it).second.size();

  count += d->pictureList.size();

  return count;
}

const Ogg::FieldListMap &Ogg::XiphComment::fieldListMap() const
{
  return d->fieldListMap;
}

PropertyMap Ogg::XiphComment::properties() const
{
  return d->fieldListMap;
}

PropertyMap Ogg::XiphComment::setProperties(const PropertyMap &properties)
{
  // check which keys are to be deleted
  StringList toRemove;
  for(FieldListMap::ConstIterator it = d->fieldListMap.begin(); it != d->fieldListMap.end(); ++it)
    if (!properties.contains(it->first))
      toRemove.append(it->first);

  for(StringList::ConstIterator it = toRemove.begin(); it != toRemove.end(); ++it)
      removeField(*it);

  // now go through keys in \a properties and check that the values match those in the xiph comment
  PropertyMap invalid;
  PropertyMap::ConstIterator it = properties.begin();
  for(; it != properties.end(); ++it)
  {
    if(!checkKey(it->first))
      invalid.insert(it->first, it->second);
    else if(!d->fieldListMap.contains(it->first) || !(it->second == d->fieldListMap[it->first])) {
      const StringList &sl = it->second;
      if(sl.size() == 0)
        // zero size string list -> remove the tag with all values
        removeField(it->first);
      else {
        // replace all strings in the list for the tag
        StringList::ConstIterator valueIterator = sl.begin();
        addField(it->first, *valueIterator, true);
        ++valueIterator;
        for(; valueIterator != sl.end(); ++valueIterator)
          addField(it->first, *valueIterator, false);
      }
    }
  }
  return invalid;
}

bool Ogg::XiphComment::checkKey(const String &key)
{
  if(key.size() < 1)
    return false;
  for(String::ConstIterator it = key.begin(); it != key.end(); it++)
      // forbid non-printable, non-ascii, '=' (#61) and '~' (#126)
      if (*it < 32 || *it >= 128 || *it == 61 || *it == 126)
        return false;
  return true;
}

String Ogg::XiphComment::vendorID() const
{
  return d->vendorID;
}

void Ogg::XiphComment::addField(const String &key, const String &value, bool replace)
{
  if(replace)
    removeField(key.upper());

  if(!key.isEmpty() && !value.isEmpty())
    d->fieldListMap[key.upper()].append(value);
}

void Ogg::XiphComment::removeField(const String &key, const String &value)
{
  if(!value.isNull()) {
    StringList::Iterator it = d->fieldListMap[key].begin();
    while(it != d->fieldListMap[key].end()) {
      if(value == *it)
        it = d->fieldListMap[key].erase(it);
      else
        it++;
    }
  }
  else
    d->fieldListMap.erase(key);
}

bool Ogg::XiphComment::contains(const String &key) const
{
  return d->fieldListMap.contains(key) && !d->fieldListMap[key].isEmpty();
}

void Ogg::XiphComment::removePicture(FLAC::Picture *picture, bool del)
{
  PictureList::Iterator it = d->pictureList.find(picture);
  if(it != d->pictureList.end())
    d->pictureList.erase(it);

  if(del)
    delete picture;
}

void Ogg::XiphComment::removePictures()
{
  PictureList newList;
  for(uint i = 0; i < d->pictureList.size(); i++) {
    delete d->pictureList[i];
  }
  d->pictureList = newList;
}

void Ogg::XiphComment::addPicture(FLAC::Picture * picture)
{
  d->pictureList.append(picture);
}

List<FLAC::Picture *> Ogg::XiphComment::pictureList()
{
  return d->pictureList;
}

ByteVector Ogg::XiphComment::render() const
{
  return render(true);
}

ByteVector Ogg::XiphComment::render(bool addFramingBit) const
{
  ByteVector data;

  // Add the vendor ID length and the vendor ID.  It's important to use the
  // length of the data(String::UTF8) rather than the length of the the string
  // since this is UTF8 text and there may be more characters in the data than
  // in the UTF16 string.

  ByteVector vendorData = d->vendorID.data(String::UTF8);

  data.append(ByteVector::fromUInt(vendorData.size(), false));
  data.append(vendorData);

  // Add the number of fields.

  data.append(ByteVector::fromUInt(fieldCount(), false));

  // Iterate over the the field lists.  Our iterator returns a
  // std::pair<String, StringList> where the first String is the field name and
  // the StringList is the values associated with that field.

  FieldListMap::ConstIterator it = d->fieldListMap.begin();
  for(; it != d->fieldListMap.end(); ++it) {

    // And now iterate over the values of the current list.

    String fieldName = (*it).first;
    StringList values = (*it).second;

    StringList::ConstIterator valuesIt = values.begin();
    for(; valuesIt != values.end(); ++valuesIt) {
      ByteVector fieldData = fieldName.data(String::UTF8);
      fieldData.append('=');
      fieldData.append((*valuesIt).data(String::UTF8));

      data.append(ByteVector::fromUInt(fieldData.size(), false));
      data.append(fieldData);
    }
  }

  for(PictureList::ConstIterator it = d->pictureList.begin(); it != d->pictureList.end(); ++it) {
    ByteVector picture = (*it)->render().toBase64();
    data.append(ByteVector::fromUInt(picture.size() + 23, false));
    data.append("METADATA_BLOCK_PICTURE=");
    data.append(picture);
  }

  // Append the "framing bit".

  if(addFramingBit)
    data.append(char(1));

  return data;
}

////////////////////////////////////////////////////////////////////////////////
// protected members
////////////////////////////////////////////////////////////////////////////////

void Ogg::XiphComment::parse(const ByteVector &data)
{
  // The first thing in the comment data is the vendor ID length, followed by a
  // UTF8 string with the vendor ID.

  uint pos = 0;

  const uint vendorLength = data.toUInt(0, false);
  pos += 4;

  d->vendorID = String(data.mid(pos, vendorLength), String::UTF8);
  pos += vendorLength;

  // Next the number of fields in the comment vector.

  const uint commentFields = data.toUInt(pos, false);
  pos += 4;

  if(commentFields > (data.size() - 8) / 4) {
    return;
  }

  for(uint i = 0; i < commentFields; i++) {

    // Each comment field is in the format "KEY=value" in a UTF8 string and has
    // 4 bytes before the text starts that gives the length.

    const uint commentLength = data.toUInt(pos, false);
    pos += 4;

    ByteVector entry = data.mid(pos, commentLength);

    pos += commentLength;

    // Don't go past data end
    if (pos > data.size())
      break;

    // Handle Pictures separately
    if(entry.startsWith("METADATA_BLOCK_PICTURE=")) {

      // Decode base64 picture data
      ByteVector picturedata = ByteVector::fromBase64(entry.mid(23));

      if(picturedata.size() == 0) {
        debug("Empty picture data. Discarding content");
        continue;
      }

      FLAC::Picture * picture = new FLAC::Picture();

      if(picture->parse(picturedata))
        d->pictureList.append(picture);
      else
        debug("Unable to parse METADATA_BLOCK_PICTURE. Discarding content.");
    }
    else {

      // Check for field separator
      int sep = entry.find('=');
      if (sep < 1) {
        debug("Discarding invalid comment field.");
        continue;
      }

      // Parse key and value
      String key = String(entry.mid(0, sep), String::UTF8);
      String value = String(entry.mid(sep + 1), String::UTF8);
      addField(key, value, false);
    }
  }
}
<commit_msg>Support reading deprecated COVERART xiphcomment<commit_after>/***************************************************************************
    copyright            : (C) 2002 - 2008 by Scott Wheeler
    email                : wheeler@kde.org
 ***************************************************************************/

/***************************************************************************
 *   This library is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Lesser General Public License version   *
 *   2.1 as published by the Free Software Foundation.                     *
 *                                                                         *
 *   This library is distributed in the hope that it will be useful, but   *
 *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
 *   Lesser General Public License for more details.                       *
 *                                                                         *
 *   You should have received a copy of the GNU Lesser General Public      *
 *   License along with this library; if not, write to the Free Software   *
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA         *
 *   02110-1301  USA                                                       *
 *                                                                         *
 *   Alternatively, this file is available under the Mozilla Public        *
 *   License Version 1.1.  You may obtain a copy of the License at         *
 *   http://www.mozilla.org/MPL/                                           *
 ***************************************************************************/

#include <tbytevector.h>
#include <tdebug.h>

#include <flacpicture.h>
#include <xiphcomment.h>
#include <tpropertymap.h>

using namespace TagLib;

typedef List<FLAC::Picture *> PictureList;

class Ogg::XiphComment::XiphCommentPrivate
{
public:
  FieldListMap fieldListMap;
  String vendorID;
  String commentField;
  PictureList pictureList;
};

////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////

Ogg::XiphComment::XiphComment() : TagLib::Tag()
{
  d = new XiphCommentPrivate;
}

Ogg::XiphComment::XiphComment(const ByteVector &data) : TagLib::Tag()
{
  d = new XiphCommentPrivate;
  parse(data);
}

Ogg::XiphComment::~XiphComment()
{
  removePictures();
  delete d;
}

String Ogg::XiphComment::title() const
{
  if(d->fieldListMap["TITLE"].isEmpty())
    return String::null;
  return d->fieldListMap["TITLE"].toString();
}

String Ogg::XiphComment::artist() const
{
  if(d->fieldListMap["ARTIST"].isEmpty())
    return String::null;
  return d->fieldListMap["ARTIST"].toString();
}

String Ogg::XiphComment::album() const
{
  if(d->fieldListMap["ALBUM"].isEmpty())
    return String::null;
  return d->fieldListMap["ALBUM"].toString();
}

String Ogg::XiphComment::comment() const
{
  if(!d->fieldListMap["DESCRIPTION"].isEmpty()) {
    d->commentField = "DESCRIPTION";
    return d->fieldListMap["DESCRIPTION"].toString();
  }

  if(!d->fieldListMap["COMMENT"].isEmpty()) {
    d->commentField = "COMMENT";
    return d->fieldListMap["COMMENT"].toString();
  }

  return String::null;
}

String Ogg::XiphComment::genre() const
{
  if(d->fieldListMap["GENRE"].isEmpty())
    return String::null;
  return d->fieldListMap["GENRE"].toString();
}

TagLib::uint Ogg::XiphComment::year() const
{
  if(!d->fieldListMap["DATE"].isEmpty())
    return d->fieldListMap["DATE"].front().toInt();
  if(!d->fieldListMap["YEAR"].isEmpty())
    return d->fieldListMap["YEAR"].front().toInt();
  return 0;
}

TagLib::uint Ogg::XiphComment::track() const
{
  if(!d->fieldListMap["TRACKNUMBER"].isEmpty())
    return d->fieldListMap["TRACKNUMBER"].front().toInt();
  if(!d->fieldListMap["TRACKNUM"].isEmpty())
    return d->fieldListMap["TRACKNUM"].front().toInt();
  return 0;
}

void Ogg::XiphComment::setTitle(const String &s)
{
  addField("TITLE", s);
}

void Ogg::XiphComment::setArtist(const String &s)
{
  addField("ARTIST", s);
}

void Ogg::XiphComment::setAlbum(const String &s)
{
  addField("ALBUM", s);
}

void Ogg::XiphComment::setComment(const String &s)
{
  addField(d->commentField.isEmpty() ? "DESCRIPTION" : d->commentField, s);
}

void Ogg::XiphComment::setGenre(const String &s)
{
  addField("GENRE", s);
}

void Ogg::XiphComment::setYear(uint i)
{
  removeField("YEAR");
  if(i == 0)
    removeField("DATE");
  else
    addField("DATE", String::number(i));
}

void Ogg::XiphComment::setTrack(uint i)
{
  removeField("TRACKNUM");
  if(i == 0)
    removeField("TRACKNUMBER");
  else
    addField("TRACKNUMBER", String::number(i));
}

bool Ogg::XiphComment::isEmpty() const
{
  FieldListMap::ConstIterator it = d->fieldListMap.begin();
  for(; it != d->fieldListMap.end(); ++it)
    if(!(*it).second.isEmpty())
      return false;

  return true;
}

TagLib::uint Ogg::XiphComment::fieldCount() const
{
  uint count = 0;

  FieldListMap::ConstIterator it = d->fieldListMap.begin();
  for(; it != d->fieldListMap.end(); ++it)
    count += (*it).second.size();

  count += d->pictureList.size();

  return count;
}

const Ogg::FieldListMap &Ogg::XiphComment::fieldListMap() const
{
  return d->fieldListMap;
}

PropertyMap Ogg::XiphComment::properties() const
{
  return d->fieldListMap;
}

PropertyMap Ogg::XiphComment::setProperties(const PropertyMap &properties)
{
  // check which keys are to be deleted
  StringList toRemove;
  for(FieldListMap::ConstIterator it = d->fieldListMap.begin(); it != d->fieldListMap.end(); ++it)
    if (!properties.contains(it->first))
      toRemove.append(it->first);

  for(StringList::ConstIterator it = toRemove.begin(); it != toRemove.end(); ++it)
      removeField(*it);

  // now go through keys in \a properties and check that the values match those in the xiph comment
  PropertyMap invalid;
  PropertyMap::ConstIterator it = properties.begin();
  for(; it != properties.end(); ++it)
  {
    if(!checkKey(it->first))
      invalid.insert(it->first, it->second);
    else if(!d->fieldListMap.contains(it->first) || !(it->second == d->fieldListMap[it->first])) {
      const StringList &sl = it->second;
      if(sl.size() == 0)
        // zero size string list -> remove the tag with all values
        removeField(it->first);
      else {
        // replace all strings in the list for the tag
        StringList::ConstIterator valueIterator = sl.begin();
        addField(it->first, *valueIterator, true);
        ++valueIterator;
        for(; valueIterator != sl.end(); ++valueIterator)
          addField(it->first, *valueIterator, false);
      }
    }
  }
  return invalid;
}

bool Ogg::XiphComment::checkKey(const String &key)
{
  if(key.size() < 1)
    return false;
  for(String::ConstIterator it = key.begin(); it != key.end(); it++)
      // forbid non-printable, non-ascii, '=' (#61) and '~' (#126)
      if (*it < 32 || *it >= 128 || *it == 61 || *it == 126)
        return false;
  return true;
}

String Ogg::XiphComment::vendorID() const
{
  return d->vendorID;
}

void Ogg::XiphComment::addField(const String &key, const String &value, bool replace)
{
  if(replace)
    removeField(key.upper());

  if(!key.isEmpty() && !value.isEmpty())
    d->fieldListMap[key.upper()].append(value);
}

void Ogg::XiphComment::removeField(const String &key, const String &value)
{
  if(!value.isNull()) {
    StringList::Iterator it = d->fieldListMap[key].begin();
    while(it != d->fieldListMap[key].end()) {
      if(value == *it)
        it = d->fieldListMap[key].erase(it);
      else
        it++;
    }
  }
  else
    d->fieldListMap.erase(key);
}

bool Ogg::XiphComment::contains(const String &key) const
{
  return d->fieldListMap.contains(key) && !d->fieldListMap[key].isEmpty();
}

void Ogg::XiphComment::removePicture(FLAC::Picture *picture, bool del)
{
  PictureList::Iterator it = d->pictureList.find(picture);
  if(it != d->pictureList.end())
    d->pictureList.erase(it);

  if(del)
    delete picture;
}

void Ogg::XiphComment::removePictures()
{
  PictureList newList;
  for(uint i = 0; i < d->pictureList.size(); i++) {
    delete d->pictureList[i];
  }
  d->pictureList = newList;
}

void Ogg::XiphComment::addPicture(FLAC::Picture * picture)
{
  d->pictureList.append(picture);
}

List<FLAC::Picture *> Ogg::XiphComment::pictureList()
{
  return d->pictureList;
}

ByteVector Ogg::XiphComment::render() const
{
  return render(true);
}

ByteVector Ogg::XiphComment::render(bool addFramingBit) const
{
  ByteVector data;

  // Add the vendor ID length and the vendor ID.  It's important to use the
  // length of the data(String::UTF8) rather than the length of the the string
  // since this is UTF8 text and there may be more characters in the data than
  // in the UTF16 string.

  ByteVector vendorData = d->vendorID.data(String::UTF8);

  data.append(ByteVector::fromUInt(vendorData.size(), false));
  data.append(vendorData);

  // Add the number of fields.

  data.append(ByteVector::fromUInt(fieldCount(), false));

  // Iterate over the the field lists.  Our iterator returns a
  // std::pair<String, StringList> where the first String is the field name and
  // the StringList is the values associated with that field.

  FieldListMap::ConstIterator it = d->fieldListMap.begin();
  for(; it != d->fieldListMap.end(); ++it) {

    // And now iterate over the values of the current list.

    String fieldName = (*it).first;
    StringList values = (*it).second;

    StringList::ConstIterator valuesIt = values.begin();
    for(; valuesIt != values.end(); ++valuesIt) {
      ByteVector fieldData = fieldName.data(String::UTF8);
      fieldData.append('=');
      fieldData.append((*valuesIt).data(String::UTF8));

      data.append(ByteVector::fromUInt(fieldData.size(), false));
      data.append(fieldData);
    }
  }

  for(PictureList::ConstIterator it = d->pictureList.begin(); it != d->pictureList.end(); ++it) {
    ByteVector picture = (*it)->render().toBase64();
    data.append(ByteVector::fromUInt(picture.size() + 23, false));
    data.append("METADATA_BLOCK_PICTURE=");
    data.append(picture);
  }

  // Append the "framing bit".

  if(addFramingBit)
    data.append(char(1));

  return data;
}

////////////////////////////////////////////////////////////////////////////////
// protected members
////////////////////////////////////////////////////////////////////////////////

void Ogg::XiphComment::parse(const ByteVector &data)
{
  // The first thing in the comment data is the vendor ID length, followed by a
  // UTF8 string with the vendor ID.

  uint pos = 0;

  const uint vendorLength = data.toUInt(0, false);
  pos += 4;

  d->vendorID = String(data.mid(pos, vendorLength), String::UTF8);
  pos += vendorLength;

  // Next the number of fields in the comment vector.

  const uint commentFields = data.toUInt(pos, false);
  pos += 4;

  if(commentFields > (data.size() - 8) / 4) {
    return;
  }

  for(uint i = 0; i < commentFields; i++) {

    // Each comment field is in the format "KEY=value" in a UTF8 string and has
    // 4 bytes before the text starts that gives the length.

    const uint commentLength = data.toUInt(pos, false);
    pos += 4;

    ByteVector entry = data.mid(pos, commentLength);

    pos += commentLength;

    // Don't go past data end
    if (pos > data.size())
      break;

    // Handle Pictures separately
    if(entry.startsWith("METADATA_BLOCK_PICTURE=")) {

      // Decode base64 picture data
      ByteVector picturedata = ByteVector::fromBase64(entry.mid(23));

      if(picturedata.size() == 0) {
        debug("Empty picture data. Discarding content");
        continue;
      }

      FLAC::Picture * picture = new FLAC::Picture();

      if(picture->parse(picturedata))
        d->pictureList.append(picture);
      else
        debug("Unable to parse METADATA_BLOCK_PICTURE. Discarding content.");
    }
    else if (entry.startsWith("COVERART=")) {

      // Decode base64 picture data
      ByteVector picturedata = ByteVector::fromBase64(entry.mid(9));

      if (picturedata.size() == 0) {
        debug("Empty coverart data. Discaring content");
        continue;
      }

      // Assume it's some type of image file
      FLAC::Picture * picture = new FLAC::Picture();
      picture->setData(picturedata);
      picture->setMimeType("image/");
      picture->setType(FLAC::Picture::Other);
      d->pictureList.append(picture);
    }
    else {

      // Check for field separator
      int sep = entry.find('=');
      if (sep < 1) {
        debug("Discarding invalid comment field.");
        continue;
      }

      // Parse key and value
      String key = String(entry.mid(0, sep), String::UTF8);
      String value = String(entry.mid(sep + 1), String::UTF8);
      addField(key, value, false);
    }
  }
}
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2017 Couchbase, Inc
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

#include "ephemeral_tombstone_purger.h"

#include "atomic.h"
#include "ep_engine.h"
#include "ep_time.h"
#include "ephemeral_vb.h"
#include "seqlist.h"

EphemeralVBucket::HTTombstonePurger::HTTombstonePurger(
        EphemeralVBucket& vbucket, rel_time_t purgeAge)
    : vbucket(vbucket),
      now(ep_current_time()),
      purgeAge(purgeAge),
      numPurgedItems(0) {
}

void EphemeralVBucket::HTTombstonePurger::visit(
        const HashTable::HashBucketLock& hbl, StoredValue* v) {
    auto* osv = v->toOrderedStoredValue();

    if (!osv->isDeleted()) {
        return;
    }

    // Skip if deleted item is too young.
    if (now - osv->getDeletedTime() < purgeAge) {
        return;
    }

    // This item should be purged. Remove from the HashTable and move over to
    // being owned by the sequence list.
    auto ownedSV = vbucket.ht.unlocked_release(hbl, v->getKey());
    {
        std::lock_guard<std::mutex> listWriteLg(
                vbucket.seqList->getListWriteLock());
        // Mark the item stale, with no replacement item
        vbucket.seqList->markItemStale(listWriteLg, std::move(ownedSV), nullptr);
    }
    ++numPurgedItems;
}

EphemeralVBucket::VBTombstonePurger::VBTombstonePurger(rel_time_t purgeAge)
    : purgeAge(purgeAge), numPurgedItems(0) {
}

void EphemeralVBucket::VBTombstonePurger::visitBucket(VBucketPtr& vb) {
    auto vbucket = dynamic_cast<EphemeralVBucket*>(vb.get());
    if (!vbucket) {
        throw std::invalid_argument(
                "VBTombstonePurger::visitBucket: Called with a non-Ephemeral "
                "bucket");
    }
    numPurgedItems += vbucket->purgeTombstones(purgeAge);
}

EphTombstonePurgerTask::EphTombstonePurgerTask(EventuallyPersistentEngine* e,
                                               EPStats& stats_)
    : GlobalTask(e, TaskId::EphTombstonePurgerTask, 0, false) {
}

bool EphTombstonePurgerTask::run() {
    if (engine->getEpStats().isShutdown) {
        return false;
    }

    LOG(EXTENSION_LOG_NOTICE,
        "%s starting with purge age:%" PRIu64,
        to_string(getDescription()).c_str(),
        uint64_t(getDeletedPurgeAge()));

    // Create a VB purger, and run across all VBuckets.
    auto start = ProcessClock::now();
    EphemeralVBucket::VBTombstonePurger purger(getDeletedPurgeAge());
    engine->getKVBucket()->visit(purger);
    auto end = ProcessClock::now();

    auto duration_ms =
            std::chrono::duration_cast<std::chrono::milliseconds>(end - start);

    LOG(EXTENSION_LOG_NOTICE,
        "%s completed. Purged %" PRIu64 " items. Took %" PRIu64
        "ms. Sleeping for %" PRIu64 " seconds.",
        to_string(getDescription()).c_str(),
        uint64_t(purger.getNumPurgedItems()),
        uint64_t(duration_ms.count()),
        uint64_t(getSleepTime()));

    snooze(getSleepTime());
    return true;
}

cb::const_char_buffer EphTombstonePurgerTask::getDescription() {
    return "Ephemeral Tombstone Purger";
}

size_t EphTombstonePurgerTask::getSleepTime() const {
    return engine->getConfiguration().getEphemeralMetadataPurgeInterval();
}

size_t EphTombstonePurgerTask::getDeletedPurgeAge() const {
    return engine->getConfiguration().getEphemeralMetadataPurgeAge();
}
<commit_msg>Reduce EphTombstonePurgerTask log to INFO<commit_after>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2017 Couchbase, Inc
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

#include "ephemeral_tombstone_purger.h"

#include "atomic.h"
#include "ep_engine.h"
#include "ep_time.h"
#include "ephemeral_vb.h"
#include "seqlist.h"

EphemeralVBucket::HTTombstonePurger::HTTombstonePurger(
        EphemeralVBucket& vbucket, rel_time_t purgeAge)
    : vbucket(vbucket),
      now(ep_current_time()),
      purgeAge(purgeAge),
      numPurgedItems(0) {
}

void EphemeralVBucket::HTTombstonePurger::visit(
        const HashTable::HashBucketLock& hbl, StoredValue* v) {
    auto* osv = v->toOrderedStoredValue();

    if (!osv->isDeleted()) {
        return;
    }

    // Skip if deleted item is too young.
    if (now - osv->getDeletedTime() < purgeAge) {
        return;
    }

    // This item should be purged. Remove from the HashTable and move over to
    // being owned by the sequence list.
    auto ownedSV = vbucket.ht.unlocked_release(hbl, v->getKey());
    {
        std::lock_guard<std::mutex> listWriteLg(
                vbucket.seqList->getListWriteLock());
        // Mark the item stale, with no replacement item
        vbucket.seqList->markItemStale(listWriteLg, std::move(ownedSV), nullptr);
    }
    ++numPurgedItems;
}

EphemeralVBucket::VBTombstonePurger::VBTombstonePurger(rel_time_t purgeAge)
    : purgeAge(purgeAge), numPurgedItems(0) {
}

void EphemeralVBucket::VBTombstonePurger::visitBucket(VBucketPtr& vb) {
    auto vbucket = dynamic_cast<EphemeralVBucket*>(vb.get());
    if (!vbucket) {
        throw std::invalid_argument(
                "VBTombstonePurger::visitBucket: Called with a non-Ephemeral "
                "bucket");
    }
    numPurgedItems += vbucket->purgeTombstones(purgeAge);
}

EphTombstonePurgerTask::EphTombstonePurgerTask(EventuallyPersistentEngine* e,
                                               EPStats& stats_)
    : GlobalTask(e, TaskId::EphTombstonePurgerTask, 0, false) {
}

bool EphTombstonePurgerTask::run() {
    if (engine->getEpStats().isShutdown) {
        return false;
    }

    LOG(EXTENSION_LOG_INFO,
        "%s starting with purge age:%" PRIu64,
        to_string(getDescription()).c_str(),
        uint64_t(getDeletedPurgeAge()));

    // Create a VB purger, and run across all VBuckets.
    auto start = ProcessClock::now();
    EphemeralVBucket::VBTombstonePurger purger(getDeletedPurgeAge());
    engine->getKVBucket()->visit(purger);
    auto end = ProcessClock::now();

    auto duration_ms =
            std::chrono::duration_cast<std::chrono::milliseconds>(end - start);

    LOG(EXTENSION_LOG_INFO,
        "%s completed. Purged %" PRIu64 " items. Took %" PRIu64
        "ms. Sleeping for %" PRIu64 " seconds.",
        to_string(getDescription()).c_str(),
        uint64_t(purger.getNumPurgedItems()),
        uint64_t(duration_ms.count()),
        uint64_t(getSleepTime()));

    snooze(getSleepTime());
    return true;
}

cb::const_char_buffer EphTombstonePurgerTask::getDescription() {
    return "Ephemeral Tombstone Purger";
}

size_t EphTombstonePurgerTask::getSleepTime() const {
    return engine->getConfiguration().getEphemeralMetadataPurgeInterval();
}

size_t EphTombstonePurgerTask::getDeletedPurgeAge() const {
    return engine->getConfiguration().getEphemeralMetadataPurgeAge();
}
<|endoftext|>


<commit_before>#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"

using namespace clang;
using namespace ento;

namespace {
class MainCallChecker : public Checker < check::PreStmt<CallExpr> > {
  mutable std::unique_ptr<BugType> BT;

public:
  void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
};
} // end anonymous namespace

void MainCallChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const {
  const Expr *Callee = CE->getCallee();
  const FunctionDecl *FD = C.getSVal(Callee).getAsFunctionDecl();

  if (!FD)
    return;

  // Get the name of the callee.
  IdentifierInfo *II = FD->getIdentifier();
  if (!II)   // if no identifier, not a simple C function
    return;

  if (II->isStr("main")) {
    ExplodedNode *N = C.generateErrorNode();
    if (!N)
      return;

    if (!BT)
      BT.reset(new BugType(this, "call to main", "example analyzer plugin"));

    std::unique_ptr<BugReport> report =
        llvm::make_unique<BugReport>(*BT, BT->getName(), N);
    report->addRange(Callee->getSourceRange());
    C.emitReport(std::move(report));
  }
}

// Register plugin!
extern "C"
void clang_registerCheckers (CheckerRegistry &registry) {
  registry.addChecker<MainCallChecker>("example.MainCallChecker", "Disallows calls to functions called main");
}

extern "C"
const char clang_analyzerAPIVersionString[] = CLANG_ANALYZER_API_VERSION_STRING;
<commit_msg>Fix the example checker plugin after r349812.<commit_after>#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"

using namespace clang;
using namespace ento;

namespace {
class MainCallChecker : public Checker < check::PreStmt<CallExpr> > {
  mutable std::unique_ptr<BugType> BT;

public:
  void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
};
} // end anonymous namespace

void MainCallChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const {
  const Expr *Callee = CE->getCallee();
  const FunctionDecl *FD = C.getSVal(Callee).getAsFunctionDecl();

  if (!FD)
    return;

  // Get the name of the callee.
  IdentifierInfo *II = FD->getIdentifier();
  if (!II)   // if no identifier, not a simple C function
    return;

  if (II->isStr("main")) {
    ExplodedNode *N = C.generateErrorNode();
    if (!N)
      return;

    if (!BT)
      BT.reset(new BugType(this, "call to main", "example analyzer plugin"));

    std::unique_ptr<BugReport> report =
        llvm::make_unique<BugReport>(*BT, BT->getName(), N);
    report->addRange(Callee->getSourceRange());
    C.emitReport(std::move(report));
  }
}

// Register plugin!
extern "C"
void clang_registerCheckers (CheckerRegistry &registry) {
  registry.addChecker<MainCallChecker>(
      "example.MainCallChecker", "Disallows calls to functions called main",
      "");
}

extern "C"
const char clang_analyzerAPIVersionString[] = CLANG_ANALYZER_API_VERSION_STRING;
<|endoftext|>


<commit_before>/** @file
    @brief Implementation

    @date 2015

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

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

// Internal Includes
#include <osvr/ClientKit/ClientKit.h>
#include <osvr/ClientKit/DisplayC.h>

// Library/third-party includes
#include <SDL.h>
#include <SDL_opengl.h>

// Standard includes
#include <iostream>
#include <stdexcept>
#include <memory>

using std::cout;
using std::cerr;
using std::endl;
namespace SDL {
/// @brief RAII wrapper for SDL startup/shutdown
class Lib {
  public:
    Lib() {
        if (SDL_Init(SDL_INIT_VIDEO) < 0) {
            cerr << "Could not initialize SDL" << endl;
            throw std::runtime_error("Could not initialize SDL");
        }
    }
    ~Lib() { SDL_Quit(); }
};

typedef std::shared_ptr<SDL_Window> WindowPtr;
template <typename... Args> inline WindowPtr createWindow(Args &&... args) {
    WindowPtr ret(SDL_CreateWindow(std::forward<Args>(args)...),
                  &SDL_DestroyWindow);
    return ret;
}
} // namespace
int main(int argc, char *argv[]) {
    SDL::Lib lib;

    // Use OpenGL 2.1
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
    auto window = SDL::createWindow("OSVR", SDL_WINDOWPOS_UNDEFINED,
                                    SDL_WINDOWPOS_UNDEFINED, 1920, 1080,
                                    SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);
    if (!window) {
        cerr << "Could not create window" << endl;
        return -1;
    }

    return 0;
}
<commit_msg>Work on SDL example.<commit_after>/** @file
    @brief Implementation

    @date 2015

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

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

// Internal Includes
#include <osvr/ClientKit/ClientKit.h>
#include <osvr/ClientKit/DisplayC.h>

// Library/third-party includes
#include <SDL.h>
#include <SDL_opengl.h>

// Standard includes
#include <iostream>
#include <stdexcept>
#include <memory>

using std::cout;
using std::cerr;
using std::endl;
namespace SDL {
/// @brief RAII wrapper for SDL startup/shutdown
class Lib {
  public:
    Lib() {
        if (SDL_Init(SDL_INIT_VIDEO) < 0) {
            cerr << "Could not initialize SDL" << endl;
            throw std::runtime_error(std::string("Could not initialize SDL") +
                                     SDL_GetError());
        }
    }
    ~Lib() { SDL_Quit(); }
};

/// @brief RAII wrapper for SDL text input start/stop.
class TextInput {
  public:
    TextInput() { SDL_StartTextInput(); }
    ~TextInput() { SDL_StopTextInput(); }
};
typedef std::shared_ptr<SDL_Window> WindowPtr;
template <typename... Args> inline WindowPtr createWindow(Args &&... args) {
    WindowPtr ret(SDL_CreateWindow(std::forward<Args>(args)...),
                  &SDL_DestroyWindow);
    return ret;
}

/// @brief RAII wrapper for SDL OpenGL context.
class GLContext {
  public:
    template <typename... Args> GLContext(Args &&... args) {
        m_context = SDL_GL_CreateContext(std::forward<Args>(args)...);
    }

    SDL_GLContext &operator*() { return m_context; }
    SDL_GLContext const &operator*() const { return m_context; }

    ~GLContext() { SDL_GL_DeleteContext(m_context); }

  private:
    SDL_GLContext m_context;
};
} // namespace SDL

static auto const WIDTH = 1920;
static auto const HEIGHT = 1080;

// Annoyingly a preprocessor macro is the only "good" way to do this quickly and
// easily
#define CHECK_SDL_POINTER_RESULT(ptr, action)                                  \
    do {                                                                       \
        if (!ptr) {                                                            \
            cerr << "Could not " action ": " << SDL_GetError() << endl;        \
            std::exit(-1);                                                     \
        }                                                                      \
    } while (0)
#define CHECK_SDL_NEGATIVE_RESULT(op, action)                                  \
    do {                                                                       \
        if ((op) < 0) {                                                        \
            cerr << "Could not " action ": " << SDL_GetError() << endl;        \
            std::exit(-1);                                                     \
        }                                                                      \
    } while (0)

void renderScene() {
    /// @todo draw a cube in the world here.
}
void render(OSVR_DisplayConfig disp) {
    OSVR_ViewerCount viewers;
    osvrClientGetNumViewers(disp, &viewers);

    for (OSVR_ViewerCount viewer = 0; viewer < viewers; ++viewer) {
        OSVR_EyeCount eyes;
        osvrClientGetNumEyesForViewer(disp, viewer, &eyes);

        for (OSVR_EyeCount eye = 0; eye < eyes; ++eye) {
            OSVR_SurfaceCount surfaces;
            osvrClientGetNumSurfacesForViewerEye(disp, viewer, eye, &surfaces);
#if 0
            /// Fill in the ModelView transform based on the eye pose
            /// @todo
            glMatrixMode(GL_MODELVIEW);
            glLoadIdentity();
            glMultMatrixd(modelView);
#endif
            for (OSVR_SurfaceCount surface = 0; surface < surfaces; ++surface) {
                cout << "Viewer " << viewer << ", Eye " << int(eye)
                     << ", Surface " << surface << endl;

#if 0
                // Set the OpenGL viewport based on the one we computed.
                glViewport(static_cast<GLint>(m_viewport.left),
                    static_cast<GLint>(m_viewport.lower),
                    static_cast<GLsizei>(m_viewport.width),
                    static_cast<GLsizei>(m_viewport.height));
                // Set the OpenGL projection matrix based on the one we
                // computed.
                glMatrixMode(GL_PROJECTION);
                glLoadIdentity();
                glMultMatrixd(projection);
                // Set the matrix mode to ModelView, so render code doesn't mess with
                // the projection matrix on accident.
                glMatrixMode(GL_MODELVIEW);

#endif
                renderScene();
            }
        }
    }
}
int main(int argc, char *argv[]) {
    // Open SDL
    SDL::Lib lib;

    // Use OpenGL 2.1
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);

    // Create a window
    auto window = SDL::createWindow("OSVR", SDL_WINDOWPOS_UNDEFINED,
                                    SDL_WINDOWPOS_UNDEFINED, WIDTH, HEIGHT,
                                    SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);
    CHECK_SDL_POINTER_RESULT(window, "create window");

    // Create an OpenGL context and make it current.
    SDL::GLContext glctx(window.get());

    // Turn on V-SYNC
    SDL_GL_SetSwapInterval(1);

    // Start OSVR and get OSVR display config
    osvr::clientkit::ClientContext ctx("com.osvr.example.sdlopengl");
    OSVR_DisplayConfig display;
    osvrClientGetDisplay(ctx.get(), &display);

    // Event handler
    SDL_Event e;
    SDL::TextInput textinput;
    bool quit = false;
    while (!quit) {
        // Handle all queued events
        while (SDL_PollEvent(&e) != 0) {
            if (e.type == SDL_QUIT) {
                quit = true;
            }
        }

        // Update OSVR
        ctx.update();

        // Render
        render(display);

        // Swap buffers
        SDL_GL_SwapWindow(window.get());
    }

    return 0;
}
<|endoftext|>