<commit_before>/* This file is part of Strigi Desktop Search
 *
 * Copyright (C) 2006 Jos van den Oever <jos@vandenoever.info>
 *               2007 Tobias Pfeiffer <tgpfeiffer@web.de>
 *               2009 Evgeny Egorochkin <phreedom.stdin@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "flacthroughanalyzer.h"
#include <strigi/strigiconfig.h>
#include "analysisresult.h"
#include "textutils.h"
#include <iostream>
#include <cctype>
#include <cstring>
using namespace Strigi;
using namespace std;

#define NMM_PROPOSAL "http://www.semanticdesktop.org/ontologies/nmm#"

const string
    typePropertyName(
	"http://www.w3.org/1999/02/22-rdf-syntax-ns#type"),
    fullnamePropertyName(
	"http://www.semanticdesktop.org/ontologies/2007/03/22/nco#fullname"),
    titlePropertyName(
	"http://www.semanticdesktop.org/ontologies/2007/01/19/nie#title"),

    musicClassName(
	NMM_PROPOSAL "MusicPiece"),
    albumClassName(
	NMM_PROPOSAL "MusicAlbum"),
    contactClassName(
	"http://www.semanticdesktop.org/ontologies/2007/03/22/nco#Contact");

void
FlacThroughAnalyzerFactory::registerFields(FieldRegister& r) {
    fields["title"] = r.registerField(titlePropertyName);
    albumField = r.registerField(NMM_PROPOSAL "musicAlbum");
    artistField = r.registerField("http://www.semanticdesktop.org/ontologies/2007/03/22/nco#creator");
    fields["genre"] = r.registerField("http://freedesktop.org/standards/xesam/1.0/core#genre");
    fields["codec"] = r.registerField("http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#codec");
    composerField = r.registerField(NMM_PROPOSAL "composer");
    performerField = r.registerField(NMM_PROPOSAL "performer");
    fields["date"] = r.registerField("http://www.semanticdesktop.org/ontologies/2007/01/19/nie#contentCreated");
    fields["description"] = r.registerField("http://www.semanticdesktop.org/ontologies/2007/01/19/nie#description");
    fields["tracknumber"] = r.registerField(NMM_PROPOSAL "trackNumber");

    fields["version"] = r.registerField("http://www.semanticdesktop.org/ontologies/2007/01/19/nie#version");
    fields["isrc"] = r.registerField(NMM_PROPOSAL "internationalStandardRecordingCode");
    fields["copyright"] = r.registerField("http://www.semanticdesktop.org/ontologies/2007/01/19/nie#copyright");
    fields["license"] = r.registerField("http://www.semanticdesktop.org/ontologies/2007/01/19/nie#license");

// ogg spec fields left unimplemented: ORGANIZATION, LOCATION, CONTACT

    fields["type"] = r.typeField;
}

#undef NMM_PROPOSAL

void
FlacThroughAnalyzer::setIndexable(AnalysisResult* i) {
    indexable = i;
}
InputStream*
FlacThroughAnalyzer::connectInputStream(InputStream* in) {
    if(!in) {
        return in;
    }
    const char* buf;
    char    blocktype;
    int32_t nreq = 8;
    int32_t nread = in->read(buf, nreq, nreq);
    int32_t blocksize = 4;
    // check the header for Flac signature
    // the first ogg page starts at position 0, the second at position 58
    if (nread < nreq || strncmp("fLaC", buf,4)) {
	in->reset(0);
        return in;
    }

    cerr<< "found a flac file!";
    do {
      blocktype = buf[blocksize];
      blocksize = readBigEndianUInt32(buf+blocksize)& 0xFFFFFF;

      //if this isn't the last block, read the header of the next block as well
      nreq = (blocktype & 0x80 ? blocksize : blocksize+4);

      nread = in->read(buf, nreq, nreq);

      // we are looking for the comments block only
      if ((blocktype&0x7F)==4) {
	const char *p2 = buf + 4 + readLittleEndianUInt32(buf); //skip vendor string. maybe put it into metadata as soon as there's some place for it
	const char *end = buf + blocksize;
	uint32_t nfields = readLittleEndianUInt32(p2);
	// read all the comments
	p2 += 4;
	for (uint32_t i = 0; p2 < end && i < nfields; ++i) {
	    // read the comment length
	    uint32_t size = readLittleEndianUInt32(p2);
	    p2 += 4;
	    if (size <= (uint32_t)(end - p2)) {
		uint32_t eq = 1;
		while (eq < size && p2[eq] != '=') eq++;
		if (size > eq) {
		    string name(p2, eq);
		    // convert field name to lower case
		    const int length = name.length();
		    for(int k=0; k!=length; ++k) {
			name[k] = std::tolower(name[k]);
		    }
		    // check if we can handle this field and if so handle it
		    map<string, const RegisteredField*>::const_iterator iter
			= factory->fields.find(name);
		    string value(p2+eq+1, size-eq-1);
		    if (iter != factory->fields.end()) {
			indexable->addValue(iter->second, value);
		    } else if(name=="artist") {
			string artistUri = indexable->newAnonymousUri();

			indexable->addValue(factory->artistField, artistUri);
			indexable->addTriplet(artistUri, typePropertyName, contactClassName);
			indexable->addTriplet(artistUri, fullnamePropertyName, value);
		    } else if(name=="album") {
			string albumUri = indexable->newAnonymousUri();

			indexable->addValue(factory->albumField, albumUri);
			indexable->addTriplet(albumUri, typePropertyName, albumClassName);
			indexable->addTriplet(albumUri, titlePropertyName, value);
		    } else if(name=="composer") {
			string composerUri = indexable->newAnonymousUri();

			indexable->addValue(factory->composerField, composerUri);
			indexable->addTriplet(composerUri, typePropertyName, contactClassName);
			indexable->addTriplet(composerUri, fullnamePropertyName, value);
		    } else if(name=="performer") {
			string performerUri = indexable->newAnonymousUri();

			indexable->addValue(factory->performerField, performerUri);
			indexable->addTriplet(performerUri, typePropertyName, contactClassName);
			indexable->addTriplet(performerUri, fullnamePropertyName, value);
		    }
		}
	    } else {
		cerr << "problem with tag size of " << size << endl;
		in->reset(0);
		return in;
	    }
	    p2 += size;
	}
	// set the "codec" value
	indexable->addValue(factory->fields.find("codec")->second, "FLAC");
	indexable->addValue(factory->fields.find("type")->second, musicClassName);
      }
    } while( !(blocktype & 0x80) );

    in->reset(0);
    return in;
}
bool
FlacThroughAnalyzer::isReadyWithStream() {
    return true;
}
<commit_msg>A quick security(buffer oveflow) fix for the FLAC analyzer.<commit_after>/* This file is part of Strigi Desktop Search
 *
 * Copyright (C) 2006 Jos van den Oever <jos@vandenoever.info>
 *               2007 Tobias Pfeiffer <tgpfeiffer@web.de>
 *               2009 Evgeny Egorochkin <phreedom.stdin@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "flacthroughanalyzer.h"
#include <strigi/strigiconfig.h>
#include "analysisresult.h"
#include "textutils.h"
#include <iostream>
#include <cctype>
#include <cstring>
using namespace Strigi;
using namespace std;

#define NMM_PROPOSAL "http://www.semanticdesktop.org/ontologies/nmm#"

const string
    typePropertyName(
	"http://www.w3.org/1999/02/22-rdf-syntax-ns#type"),
    fullnamePropertyName(
	"http://www.semanticdesktop.org/ontologies/2007/03/22/nco#fullname"),
    titlePropertyName(
	"http://www.semanticdesktop.org/ontologies/2007/01/19/nie#title"),

    musicClassName(
	NMM_PROPOSAL "MusicPiece"),
    albumClassName(
	NMM_PROPOSAL "MusicAlbum"),
    contactClassName(
	"http://www.semanticdesktop.org/ontologies/2007/03/22/nco#Contact");

void
FlacThroughAnalyzerFactory::registerFields(FieldRegister& r) {
    fields["title"] = r.registerField(titlePropertyName);
    albumField = r.registerField(NMM_PROPOSAL "musicAlbum");
    artistField = r.registerField("http://www.semanticdesktop.org/ontologies/2007/03/22/nco#creator");
    fields["genre"] = r.registerField("http://freedesktop.org/standards/xesam/1.0/core#genre");
    fields["codec"] = r.registerField("http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#codec");
    composerField = r.registerField(NMM_PROPOSAL "composer");
    performerField = r.registerField(NMM_PROPOSAL "performer");
    fields["date"] = r.registerField("http://www.semanticdesktop.org/ontologies/2007/01/19/nie#contentCreated");
    fields["description"] = r.registerField("http://www.semanticdesktop.org/ontologies/2007/01/19/nie#description");
    fields["tracknumber"] = r.registerField(NMM_PROPOSAL "trackNumber");

    fields["version"] = r.registerField("http://www.semanticdesktop.org/ontologies/2007/01/19/nie#version");
    fields["isrc"] = r.registerField(NMM_PROPOSAL "internationalStandardRecordingCode");
    fields["copyright"] = r.registerField("http://www.semanticdesktop.org/ontologies/2007/01/19/nie#copyright");
    fields["license"] = r.registerField("http://www.semanticdesktop.org/ontologies/2007/01/19/nie#license");

// ogg spec fields left unimplemented: ORGANIZATION, LOCATION, CONTACT

    fields["type"] = r.typeField;
}

#undef NMM_PROPOSAL

void
FlacThroughAnalyzer::setIndexable(AnalysisResult* i) {
    indexable = i;
}
InputStream*
FlacThroughAnalyzer::connectInputStream(InputStream* in) {
    if(!in) {
        return in;
    }
    const char* buf;
    char    blocktype;
    int32_t nreq = 8;
    int32_t nread = in->read(buf, nreq, nreq);
    int32_t blocksize = 4;
    // check the header for Flac signature
    // the first ogg page starts at position 0, the second at position 58
    if (nread < nreq || strncmp("fLaC", buf,4)) {
	in->reset(0);
        return in;
    }

    cerr<< "found a flac file!";
    do {
      blocktype = buf[blocksize];
      blocksize = readBigEndianUInt32(buf+blocksize)& 0xFFFFFF;

      //if this isn't the last block, read the header of the next block as well
      nreq = (blocktype & 0x80 ? blocksize : blocksize+4);

      nread = in->read(buf, nreq, nreq);
      if (nread!=nreq) {
	in->reset(0);
        return in;
      }

      // we are looking for the comments block only
      if ((blocktype&0x7F)==4) {
	const char *p2 = buf + 4 + readLittleEndianUInt32(buf); //skip vendor string. maybe put it into metadata as soon as there's some place for it
	const char *end = buf + blocksize;
	uint32_t nfields = readLittleEndianUInt32(p2);
	// read all the comments
	p2 += 4;
	for (uint32_t i = 0; p2 < end && i < nfields; ++i) {
	    // read the comment length
	    uint32_t size = readLittleEndianUInt32(p2);
	    p2 += 4;
	    if (size <= (uint32_t)(end - p2)) {
		uint32_t eq = 1;
		while (eq < size && p2[eq] != '=') eq++;
		if (size > eq) {
		    string name(p2, eq);
		    // convert field name to lower case
		    const int length = name.length();
		    for(int k=0; k!=length; ++k) {
			name[k] = std::tolower(name[k]);
		    }
		    // check if we can handle this field and if so handle it
		    map<string, const RegisteredField*>::const_iterator iter
			= factory->fields.find(name);
		    string value(p2+eq+1, size-eq-1);
		    if (iter != factory->fields.end()) {
			indexable->addValue(iter->second, value);
		    } else if(name=="artist") {
			string artistUri = indexable->newAnonymousUri();

			indexable->addValue(factory->artistField, artistUri);
			indexable->addTriplet(artistUri, typePropertyName, contactClassName);
			indexable->addTriplet(artistUri, fullnamePropertyName, value);
		    } else if(name=="album") {
			string albumUri = indexable->newAnonymousUri();

			indexable->addValue(factory->albumField, albumUri);
			indexable->addTriplet(albumUri, typePropertyName, albumClassName);
			indexable->addTriplet(albumUri, titlePropertyName, value);
		    } else if(name=="composer") {
			string composerUri = indexable->newAnonymousUri();

			indexable->addValue(factory->composerField, composerUri);
			indexable->addTriplet(composerUri, typePropertyName, contactClassName);
			indexable->addTriplet(composerUri, fullnamePropertyName, value);
		    } else if(name=="performer") {
			string performerUri = indexable->newAnonymousUri();

			indexable->addValue(factory->performerField, performerUri);
			indexable->addTriplet(performerUri, typePropertyName, contactClassName);
			indexable->addTriplet(performerUri, fullnamePropertyName, value);
		    }
		}
	    } else {
		cerr << "problem with tag size of " << size << endl;
		in->reset(0);
		return in;
	    }
	    p2 += size;
	}
	// set the "codec" value
	indexable->addValue(factory->fields.find("codec")->second, "FLAC");
	indexable->addValue(factory->fields.find("type")->second, musicClassName);
      }
    } while( !(blocktype & 0x80) );

    in->reset(0);
    return in;
}
bool
FlacThroughAnalyzer::isReadyWithStream() {
    return true;
}
<|endoftext|>


<commit_before>#include <babylon/misc/highdynamicrange/hdr_tools.h>

#include <babylon/babylon_stl_util.h>
#include <babylon/misc/highdynamicrange/panorama_to_cube_map_tools.h>
#include <babylon/misc/string_tools.h>

namespace BABYLON {

float HDRTools::Ldexp(float mantissa, float exponent)
{
  if (exponent > 1023.f) {
    return mantissa * std::pow(2.f, 1023.f) * std::pow(2.f, exponent - 1023.f);
  }

  if (exponent < -1074.f) {
    return mantissa * std::pow(2.f, -1074.f) * std::pow(2.f, exponent + 1074.f);
  }

  return mantissa * std::pow(2.f, exponent);
}

void HDRTools::Rgbe2float(Float32Array& float32array, float red, float green, float blue,
                          float exponent, size_t index)
{
  if (exponent > 0.f) { /*nonzero pixel*/
    exponent = Ldexp(1.f, exponent - (128.f + 8.f));

    float32array[index + 0] = red * exponent;
    float32array[index + 1] = green * exponent;
    float32array[index + 2] = blue * exponent;
  }
  else {
    float32array[index + 0] = 0.f;
    float32array[index + 1] = 0.f;
    float32array[index + 2] = 0.f;
  }
}

std::string HDRTools::readStringLine(const Uint8Array& uint8array, size_t startIndex)
{
  std::ostringstream line;
  std::string character;

  for (size_t i = startIndex; i < uint8array.size() - startIndex; ++i) {
    character = StringTools::fromCharCode(uint8array[i]);

    if (character == "\n") {
      break;
    }

    line << character;
  }

  return line.str();
}

HDRInfo HDRTools::RGBE_ReadHeader(const Uint8Array& uint8array)
{
  HDRInfo headerInfo;

  auto height = 0ull;
  auto width  = 0ull;

  auto line = readStringLine(uint8array, 0);
  if (line.at(0) != '#' || line.at(1) != '?') {
    throw std::runtime_error("Bad HDR Format.");
  }

  auto endOfHeader = false;
  auto findFormat  = false;
  auto lineIndex   = 0ull;

  do {
    lineIndex += (line.size() + 1);
    line = readStringLine(uint8array, lineIndex);

    if (line == "FORMAT=32-bit_rle_rgbe") {
      findFormat = true;
    }
    else if (line.empty()) {
      endOfHeader = true;
    }
  } while (!endOfHeader);

  if (!findFormat) {
    throw std::runtime_error("HDR Bad header format, unsupported FORMAT");
  }

  lineIndex += (line.size() + 1);
  line = readStringLine(uint8array, lineIndex);

  const std::regex sizeRegexp("^\\-Y (.*) \\+X (.*)$", std::regex::optimize);
  std::smatch match;

  if (std::regex_search(line, match, sizeRegexp) && (match.size() == 3)) {
    // Shader include found
    width  = std::stoul(match.str(2));
    height = std::stoul(match.str(1));
  }
  else {
    throw std::runtime_error("HDR Bad header format, no size");
  }

  if (width < 8 || width > 0x7fff) {
    throw std::runtime_error("HDR Bad header format, unsupported size");
  }

  lineIndex += (line.size() + 1);

  headerInfo.height       = height;
  headerInfo.width        = width;
  headerInfo.dataPosition = lineIndex;

  return headerInfo;
}

CubeMapInfo HDRTools::GetCubeMapTextureData(const Uint8Array& buffer, size_t size)
{
  auto hdrInfo = RGBE_ReadHeader(buffer);
  auto data    = RGBE_ReadPixels(buffer, hdrInfo);

  return PanoramaToCubeMapTools::ConvertPanoramaToCubemap(data, hdrInfo.width, hdrInfo.height,
                                                          size);
}

Float32Array HDRTools::RGBE_ReadPixels(const Uint8Array& uint8array, const HDRInfo& hdrInfo)
{
  return RGBE_ReadPixels_RLE(uint8array, hdrInfo);
}

Float32Array HDRTools::RGBE_ReadPixels_RLE(const Uint8Array& uint8array, const HDRInfo& hdrInfo)
{
  auto num_scanlines  = hdrInfo.height;
  auto scanline_width = hdrInfo.width;

  std::uint8_t a, b, c, d, count;
  auto dataIndex = hdrInfo.dataPosition;
  auto index = 0ull, endIndex = 0ull, i = 0ull;

  ArrayBuffer scanLineArrayBuffer(scanline_width * 4); // four channel R G B E
  auto scanLineArray = stl_util::to_array<uint8_t>(scanLineArrayBuffer);

  // 3 channels of 4 bytes per pixel in float.
  ArrayBuffer resultBuffer(hdrInfo.width * hdrInfo.height * 4 * 3);
  auto resultArray = stl_util::to_array<float>(resultBuffer);

  // read in each successive scanline
  while (num_scanlines > 0) {
    a = uint8array[dataIndex++];
    b = uint8array[dataIndex++];
    c = uint8array[dataIndex++];
    d = uint8array[dataIndex++];

    if (a != 2 || b != 2 || (c & 0x80) || hdrInfo.width < 8 || hdrInfo.width > 32767) {
      return HDRTools::RGBE_ReadPixels_NOT_RLE(uint8array, hdrInfo);
    }

    if (static_cast<size_t>((c << 8) | d) != scanline_width) {
      throw std::runtime_error("HDR Bad header format, wrong scan line width");
    }

    index = 0;

    // read each of the four channels for the scanline into the buffer
    for (i = 0; i < 4; i++) {
      endIndex = (i + 1) * scanline_width;

      while (index < endIndex) {
        a = uint8array[dataIndex++];
        b = uint8array[dataIndex++];

        if (a > 128) {
          // a run of the same value
          count = static_cast<std::uint8_t>(a - 128);
          if ((count == 0) || (count > endIndex - index)) {
            throw std::runtime_error("HDR Bad Format, bad scanline data (run)");
          }

          while (count-- > 0) {
            scanLineArray[index++] = b;
          }
        }
        else {
          // a non-run
          count = a;
          if ((count == 0) || (count > endIndex - index)) {
            throw std::runtime_error("HDR Bad Format, bad scanline data (non-run)");
          }

          scanLineArray[index++] = b;
          if (--count > 0) {
            for (size_t j = 0; j < count; ++j) {
              scanLineArray[index++] = uint8array[dataIndex++];
            }
          }
        }
      }
    }

    // now convert data from buffer into floats
    for (i = 0; i < scanline_width; ++i) {
      a = scanLineArray[i];
      b = scanLineArray[i + scanline_width];
      c = scanLineArray[i + 2 * scanline_width];
      d = scanLineArray[i + 3 * scanline_width];

      Rgbe2float(resultArray, a, b, c, d,
                 (hdrInfo.height - num_scanlines) * scanline_width * 3 + i * 3);
    }

    --num_scanlines;
  }

  return resultArray;
}

Float32Array HDRTools::RGBE_ReadPixels_NOT_RLE(const Uint8Array& uint8array, const HDRInfo& hdrInfo)
{
  // this file is not run length encoded
  // read values sequentially

  auto num_scanlines        = hdrInfo.height;
  const auto scanline_width = hdrInfo.width;

  uint8_t a = 0, b = 0, c = 0, d = 0;
  auto i         = 0ull;
  auto dataIndex = hdrInfo.dataPosition;

  // 3 channels of 4 bytes per pixel in float.
  Float32Array resultArray(hdrInfo.width * hdrInfo.height * 4 * 3);

  // read in each successive scanline
  while (num_scanlines > 0) {
    for (i = 0; i < hdrInfo.width; i++) {
      a = uint8array[dataIndex++];
      b = uint8array[dataIndex++];
      c = uint8array[dataIndex++];
      d = uint8array[dataIndex++];

      Rgbe2float(resultArray, //
                 a, b, c, d,  //
                 (hdrInfo.height - num_scanlines) * scanline_width * 3 + i * 3);
    }

    --num_scanlines;
  }

  return resultArray;
}

} // end of namespace BABYLON
<commit_msg>const correctness<commit_after>#include <babylon/misc/highdynamicrange/hdr_tools.h>

#include <babylon/babylon_stl_util.h>
#include <babylon/misc/highdynamicrange/panorama_to_cube_map_tools.h>
#include <babylon/misc/string_tools.h>

namespace BABYLON {

float HDRTools::Ldexp(float mantissa, float exponent)
{
  if (exponent > 1023.f) {
    return mantissa * std::pow(2.f, 1023.f) * std::pow(2.f, exponent - 1023.f);
  }

  if (exponent < -1074.f) {
    return mantissa * std::pow(2.f, -1074.f) * std::pow(2.f, exponent + 1074.f);
  }

  return mantissa * std::pow(2.f, exponent);
}

void HDRTools::Rgbe2float(Float32Array& float32array, float red, float green, float blue,
                          float exponent, size_t index)
{
  if (exponent > 0.f) { /*nonzero pixel*/
    exponent = Ldexp(1.f, exponent - (128.f + 8.f));

    float32array[index + 0] = red * exponent;
    float32array[index + 1] = green * exponent;
    float32array[index + 2] = blue * exponent;
  }
  else {
    float32array[index + 0] = 0.f;
    float32array[index + 1] = 0.f;
    float32array[index + 2] = 0.f;
  }
}

std::string HDRTools::readStringLine(const Uint8Array& uint8array, size_t startIndex)
{
  std::ostringstream line;
  std::string character;

  for (size_t i = startIndex; i < uint8array.size() - startIndex; ++i) {
    character = StringTools::fromCharCode(uint8array[i]);

    if (character == "\n") {
      break;
    }

    line << character;
  }

  return line.str();
}

HDRInfo HDRTools::RGBE_ReadHeader(const Uint8Array& uint8array)
{
  HDRInfo headerInfo;

  auto height = 0ull;
  auto width  = 0ull;

  auto line = readStringLine(uint8array, 0);
  if (line.at(0) != '#' || line.at(1) != '?') {
    throw std::runtime_error("Bad HDR Format.");
  }

  auto endOfHeader = false;
  auto findFormat  = false;
  auto lineIndex   = 0ull;

  do {
    lineIndex += (line.size() + 1);
    line = readStringLine(uint8array, lineIndex);

    if (line == "FORMAT=32-bit_rle_rgbe") {
      findFormat = true;
    }
    else if (line.empty()) {
      endOfHeader = true;
    }
  } while (!endOfHeader);

  if (!findFormat) {
    throw std::runtime_error("HDR Bad header format, unsupported FORMAT");
  }

  lineIndex += (line.size() + 1);
  line = readStringLine(uint8array, lineIndex);

  const std::regex sizeRegexp("^\\-Y (.*) \\+X (.*)$", std::regex::optimize);
  std::smatch match;

  if (std::regex_search(line, match, sizeRegexp) && (match.size() == 3)) {
    // Shader include found
    width  = std::stoul(match.str(2));
    height = std::stoul(match.str(1));
  }
  else {
    throw std::runtime_error("HDR Bad header format, no size");
  }

  if (width < 8 || width > 0x7fff) {
    throw std::runtime_error("HDR Bad header format, unsupported size");
  }

  lineIndex += (line.size() + 1);

  headerInfo.height       = height;
  headerInfo.width        = width;
  headerInfo.dataPosition = lineIndex;

  return headerInfo;
}

CubeMapInfo HDRTools::GetCubeMapTextureData(const Uint8Array& buffer, size_t size)
{
  const auto hdrInfo = RGBE_ReadHeader(buffer);
  const auto data    = RGBE_ReadPixels(buffer, hdrInfo);

  return PanoramaToCubeMapTools::ConvertPanoramaToCubemap(data, hdrInfo.width, hdrInfo.height,
                                                          size);
}

Float32Array HDRTools::RGBE_ReadPixels(const Uint8Array& uint8array, const HDRInfo& hdrInfo)
{
  return RGBE_ReadPixels_RLE(uint8array, hdrInfo);
}

Float32Array HDRTools::RGBE_ReadPixels_RLE(const Uint8Array& uint8array, const HDRInfo& hdrInfo)
{
  auto num_scanlines        = hdrInfo.height;
  const auto scanline_width = hdrInfo.width;

  std::uint8_t a, b, c, d, count;
  auto dataIndex = hdrInfo.dataPosition;
  auto index = 0ull, endIndex = 0ull, i = 0ull;

  ArrayBuffer scanLineArrayBuffer(scanline_width * 4); // four channel R G B E
  auto scanLineArray = stl_util::to_array<uint8_t>(scanLineArrayBuffer);

  // 3 channels of 4 bytes per pixel in float.
  ArrayBuffer resultBuffer(hdrInfo.width * hdrInfo.height * 4 * 3);
  auto resultArray = stl_util::to_array<float>(resultBuffer);

  // read in each successive scanline
  while (num_scanlines > 0) {
    a = uint8array[dataIndex++];
    b = uint8array[dataIndex++];
    c = uint8array[dataIndex++];
    d = uint8array[dataIndex++];

    if (a != 2 || b != 2 || (c & 0x80) || hdrInfo.width < 8 || hdrInfo.width > 32767) {
      return HDRTools::RGBE_ReadPixels_NOT_RLE(uint8array, hdrInfo);
    }

    if (static_cast<size_t>((c << 8) | d) != scanline_width) {
      throw std::runtime_error("HDR Bad header format, wrong scan line width");
    }

    index = 0;

    // read each of the four channels for the scanline into the buffer
    for (i = 0; i < 4; i++) {
      endIndex = (i + 1) * scanline_width;

      while (index < endIndex) {
        a = uint8array[dataIndex++];
        b = uint8array[dataIndex++];

        if (a > 128) {
          // a run of the same value
          count = static_cast<std::uint8_t>(a - 128);
          if ((count == 0) || (count > endIndex - index)) {
            throw std::runtime_error("HDR Bad Format, bad scanline data (run)");
          }

          while (count-- > 0) {
            scanLineArray[index++] = b;
          }
        }
        else {
          // a non-run
          count = a;
          if ((count == 0) || (count > endIndex - index)) {
            throw std::runtime_error("HDR Bad Format, bad scanline data (non-run)");
          }

          scanLineArray[index++] = b;
          if (--count > 0) {
            for (size_t j = 0; j < count; ++j) {
              scanLineArray[index++] = uint8array[dataIndex++];
            }
          }
        }
      }
    }

    // now convert data from buffer into floats
    for (i = 0; i < scanline_width; ++i) {
      a = scanLineArray[i];
      b = scanLineArray[i + scanline_width];
      c = scanLineArray[i + 2 * scanline_width];
      d = scanLineArray[i + 3 * scanline_width];

      Rgbe2float(resultArray, a, b, c, d,
                 (hdrInfo.height - num_scanlines) * scanline_width * 3 + i * 3);
    }

    --num_scanlines;
  }

  return resultArray;
}

Float32Array HDRTools::RGBE_ReadPixels_NOT_RLE(const Uint8Array& uint8array, const HDRInfo& hdrInfo)
{
  // this file is not run length encoded
  // read values sequentially

  auto num_scanlines        = hdrInfo.height;
  const auto scanline_width = hdrInfo.width;

  uint8_t a = 0, b = 0, c = 0, d = 0;
  auto i         = 0ull;
  auto dataIndex = hdrInfo.dataPosition;

  // 3 channels of 4 bytes per pixel in float.
  Float32Array resultArray(hdrInfo.width * hdrInfo.height * 4 * 3);

  // read in each successive scanline
  while (num_scanlines > 0) {
    for (i = 0; i < hdrInfo.width; i++) {
      a = uint8array[dataIndex++];
      b = uint8array[dataIndex++];
      c = uint8array[dataIndex++];
      d = uint8array[dataIndex++];

      Rgbe2float(resultArray, //
                 a, b, c, d,  //
                 (hdrInfo.height - num_scanlines) * scanline_width * 3 + i * 3);
    }

    --num_scanlines;
  }

  return resultArray;
}

} // end of namespace BABYLON
<|endoftext|>


<commit_before>//RUN: make -C %testexecdir/../../clang/ test TESTSUITE=Sema CLANG=%p/clangTestUnloader.sh
<commit_msg>XFAIL clang's testsuite for now.<commit_after>//RUN: make -C %testexecdir/../../clang/ test TESTSUITE=Sema CLANG=%p/clangTestUnloader.sh
//XFAIL: *
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: tdcomp.cxx,v $
 *
 *  $Revision: 1.9 $
 *
 *  last change: $Author: obo $ $Date: 2004-06-04 02:33:08 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  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., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _STOC_RDBTDP_BASE_HXX
#include "base.hxx"
#endif

#include "registry/reader.hxx"
#include "registry/version.h"

namespace stoc_rdbtdp
{

//__________________________________________________________________________________________________
CompoundTypeDescriptionImpl::~CompoundTypeDescriptionImpl()
{
    delete _pMembers;
    delete _pMemberNames;
    g_moduleCount.modCnt.release( &g_moduleCount.modCnt );
}

// XTypeDescription
//__________________________________________________________________________________________________
TypeClass CompoundTypeDescriptionImpl::getTypeClass()
    throw(::com::sun::star::uno::RuntimeException)
{
    return _eTypeClass;
}
//__________________________________________________________________________________________________
OUString CompoundTypeDescriptionImpl::getName()
    throw(::com::sun::star::uno::RuntimeException)
{
    return _aName;
}

// XCompoundTypeDescription
//__________________________________________________________________________________________________
Reference< XTypeDescription > CompoundTypeDescriptionImpl::getBaseType()
    throw(::com::sun::star::uno::RuntimeException)
{
    if (!_xBaseTD.is() && _aBaseType.getLength())
    {
        try
        {
            Reference< XTypeDescription > xBaseTD;
            if (_xTDMgr->getByHierarchicalName( _aBaseType ) >>= xBaseTD)
            {
                MutexGuard aGuard( getMutex() );
                if (! _xBaseTD.is())
                    _xBaseTD = xBaseTD;
                return _xBaseTD;
            }
        }
        catch (NoSuchElementException &)
        {
        }
        // never try again, if no base td was found
        _aBaseType = OUString();
    }
    return _xBaseTD;
}
//__________________________________________________________________________________________________

namespace {

class TypeParameter: public WeakImplHelper1< XTypeDescription > {
public:
    explicit TypeParameter(OUString const & name): m_name(name) {}

    virtual TypeClass SAL_CALL getTypeClass() throw (RuntimeException)
    { return TypeClass_UNKNOWN; }

    virtual OUString SAL_CALL getName() throw (RuntimeException)
    { return m_name; }

private:
    OUString m_name;
};

}

Sequence< Reference< XTypeDescription > > CompoundTypeDescriptionImpl::getMemberTypes()
    throw(::com::sun::star::uno::RuntimeException)
{
    if (! _pMembers)
    {
        typereg::Reader aReader(
            _aBytes.getConstArray(), _aBytes.getLength(), false,
            TYPEREG_VERSION_1);

        sal_uInt16 nFields = aReader.getFieldCount();
        Sequence< Reference< XTypeDescription > > * pTempMembers =
            new Sequence< Reference< XTypeDescription > >( nFields );
        Reference< XTypeDescription > * pMembers = pTempMembers->getArray();

        while (nFields--)
        {
            if ((aReader.getFieldFlags(nFields) & RT_ACCESS_PARAMETERIZED_TYPE)
                != 0)
            {
                pMembers[nFields] = new TypeParameter(
                    aReader.getFieldTypeName(nFields));
            } else {
                try {
                    _xTDMgr->getByHierarchicalName(
                        aReader.getFieldTypeName(nFields).replace('/', '.'))
                            >>= pMembers[nFields];
                } catch (NoSuchElementException &) {}
                OSL_ENSURE(
                    pMembers[nFields].is(), "### compound member unknown!");
            }
        }

        ClearableMutexGuard aGuard( getMutex() );
        if (_pMembers)
        {
            aGuard.clear();
            delete pTempMembers;
        }
        else
        {
            _pMembers = pTempMembers;
        }
    }

    return *_pMembers;
}
//__________________________________________________________________________________________________
Sequence< OUString > CompoundTypeDescriptionImpl::getMemberNames()
    throw(::com::sun::star::uno::RuntimeException)
{
    if (! _pMemberNames)
    {
        typereg::Reader aReader(
            _aBytes.getConstArray(), _aBytes.getLength(), false,
            TYPEREG_VERSION_1);

        sal_uInt16 nFields = aReader.getFieldCount();
        Sequence< OUString > * pTempMemberNames = new Sequence< OUString >( nFields );
        OUString * pMemberNames = pTempMemberNames->getArray();

        while (nFields--)
        {
            pMemberNames[nFields] = aReader.getFieldName( nFields );
        }

        ClearableMutexGuard aGuard( getMutex() );
        if (_pMemberNames)
        {
            aGuard.clear();
            delete pTempMemberNames;
        }
        else
        {
            _pMemberNames = pTempMemberNames;
        }
    }
    return *_pMemberNames;
}

}

<commit_msg>INTEGRATION: CWS ooo19126 (1.9.58); FILE MERGED 2005/09/05 17:11:05 rt 1.9.58.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: tdcomp.cxx,v $
 *
 *  $Revision: 1.10 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 08:05:57 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _STOC_RDBTDP_BASE_HXX
#include "base.hxx"
#endif

#include "registry/reader.hxx"
#include "registry/version.h"

namespace stoc_rdbtdp
{

//__________________________________________________________________________________________________
CompoundTypeDescriptionImpl::~CompoundTypeDescriptionImpl()
{
    delete _pMembers;
    delete _pMemberNames;
    g_moduleCount.modCnt.release( &g_moduleCount.modCnt );
}

// XTypeDescription
//__________________________________________________________________________________________________
TypeClass CompoundTypeDescriptionImpl::getTypeClass()
    throw(::com::sun::star::uno::RuntimeException)
{
    return _eTypeClass;
}
//__________________________________________________________________________________________________
OUString CompoundTypeDescriptionImpl::getName()
    throw(::com::sun::star::uno::RuntimeException)
{
    return _aName;
}

// XCompoundTypeDescription
//__________________________________________________________________________________________________
Reference< XTypeDescription > CompoundTypeDescriptionImpl::getBaseType()
    throw(::com::sun::star::uno::RuntimeException)
{
    if (!_xBaseTD.is() && _aBaseType.getLength())
    {
        try
        {
            Reference< XTypeDescription > xBaseTD;
            if (_xTDMgr->getByHierarchicalName( _aBaseType ) >>= xBaseTD)
            {
                MutexGuard aGuard( getMutex() );
                if (! _xBaseTD.is())
                    _xBaseTD = xBaseTD;
                return _xBaseTD;
            }
        }
        catch (NoSuchElementException &)
        {
        }
        // never try again, if no base td was found
        _aBaseType = OUString();
    }
    return _xBaseTD;
}
//__________________________________________________________________________________________________

namespace {

class TypeParameter: public WeakImplHelper1< XTypeDescription > {
public:
    explicit TypeParameter(OUString const & name): m_name(name) {}

    virtual TypeClass SAL_CALL getTypeClass() throw (RuntimeException)
    { return TypeClass_UNKNOWN; }

    virtual OUString SAL_CALL getName() throw (RuntimeException)
    { return m_name; }

private:
    OUString m_name;
};

}

Sequence< Reference< XTypeDescription > > CompoundTypeDescriptionImpl::getMemberTypes()
    throw(::com::sun::star::uno::RuntimeException)
{
    if (! _pMembers)
    {
        typereg::Reader aReader(
            _aBytes.getConstArray(), _aBytes.getLength(), false,
            TYPEREG_VERSION_1);

        sal_uInt16 nFields = aReader.getFieldCount();
        Sequence< Reference< XTypeDescription > > * pTempMembers =
            new Sequence< Reference< XTypeDescription > >( nFields );
        Reference< XTypeDescription > * pMembers = pTempMembers->getArray();

        while (nFields--)
        {
            if ((aReader.getFieldFlags(nFields) & RT_ACCESS_PARAMETERIZED_TYPE)
                != 0)
            {
                pMembers[nFields] = new TypeParameter(
                    aReader.getFieldTypeName(nFields));
            } else {
                try {
                    _xTDMgr->getByHierarchicalName(
                        aReader.getFieldTypeName(nFields).replace('/', '.'))
                            >>= pMembers[nFields];
                } catch (NoSuchElementException &) {}
                OSL_ENSURE(
                    pMembers[nFields].is(), "### compound member unknown!");
            }
        }

        ClearableMutexGuard aGuard( getMutex() );
        if (_pMembers)
        {
            aGuard.clear();
            delete pTempMembers;
        }
        else
        {
            _pMembers = pTempMembers;
        }
    }

    return *_pMembers;
}
//__________________________________________________________________________________________________
Sequence< OUString > CompoundTypeDescriptionImpl::getMemberNames()
    throw(::com::sun::star::uno::RuntimeException)
{
    if (! _pMemberNames)
    {
        typereg::Reader aReader(
            _aBytes.getConstArray(), _aBytes.getLength(), false,
            TYPEREG_VERSION_1);

        sal_uInt16 nFields = aReader.getFieldCount();
        Sequence< OUString > * pTempMemberNames = new Sequence< OUString >( nFields );
        OUString * pMemberNames = pTempMemberNames->getArray();

        while (nFields--)
        {
            pMemberNames[nFields] = aReader.getFieldName( nFields );
        }

        ClearableMutexGuard aGuard( getMutex() );
        if (_pMemberNames)
        {
            aGuard.clear();
            delete pTempMemberNames;
        }
        else
        {
            _pMemberNames = pTempMemberNames;
        }
    }
    return *_pMemberNames;
}

}

<|endoftext|>


<commit_before>#include <phypp.hpp>

int phypp_main(int argc, char* argv[]) {
    if (argc < 2) {
        print("usage: median_sub <directory> <mask_catalog>");
        return 0;
    }

    std::string dir = file::directorize(argv[1]);
    vec1s files = dir+file::list_files(dir+"sci_reconstructed*-sci.fits");
    if (files.empty()) {
        files = dir+file::list_files(dir+"SCI_RECONSTRUCTED*-sci.fits");
    }

    vec1d ra, dec, size;
    if (argc > 2) {
        vec1s id;
        ascii::read_table(argv[2], ascii::find_skip(argv[2]), id, ra, dec, size);
    }

    auto ksigma = [](vec1d data) {
        double v = median(data);
        double m = 1.48*median(abs(data - v));
        vec1u idg = where(abs(data - v) < 7*m);
        return mean(data[idg]);
    };

    for (auto oname : files) {
        std::string newfile = file::get_basename(oname);
        file::copy(oname, newfile);
        fits::image fimg(newfile);
        for (uint_t i : range(1, fimg.hdu_count())) {
            fimg.reach_hdu(i);
            if (fimg.axis_count() != 3) continue;

            vec3d cube;
            fimg.read(cube);

            uint_t ny = cube.dims[1];
            uint_t nx = cube.dims[2];

            vec2b mask = replicate(true, ny, nx);

            // Mask nearby sources from the provided catalog (if any)
            if (!ra.empty()) {
                astro::wcs w(fimg.read_header());
                vec1d x, y;
                astro::ad2xy(w, ra, dec, x, y);
                x -= 1.0; y -= 1.0;
                double aspix;
                astro::get_pixel_size(w, aspix);
                vec1d r = size/aspix;

                vec2d ix = generate_img(mask.dims, [](int_t,    int_t tx) { return tx; });
                vec2d iy = generate_img(mask.dims, [](int_t ty, int_t)    { return ty; });

                for (uint_t s : range(ra)) {
                    mask = mask && sqr(x[s] - ix) + sqr(y[s] - iy) > sqr(r[s]);
                }
            }

            // Mask borders
            mask(0,_) = mask(ny-1,_) = mask(_,0) = mask(_,nx-1) = false;

            // Subtract whole IFU
            vec1u idg = where(mask);
            for (uint_t l : range(cube.dims[0])) {
                cube(l,_,_) -= ksigma(cube(l,_,_)[idg]);
            }

            fimg.update(cube);
        }
    }

    return 0;
}
<commit_msg>median_sub can now simply mask the center of the IFU<commit_after>#include <phypp.hpp>

int phypp_main(int argc, char* argv[]) {
    if (argc < 2) {
        print("usage: median_sub <directory> [options]");
        return 0;
    }

    std::string dir = file::directorize(argv[1]);
    vec1s files = dir+file::list_files(dir+"sci_reconstructed*-sci.fits");
    if (files.empty()) {
        files = dir+file::list_files(dir+"SCI_RECONSTRUCTED*-sci.fits");
    }

    bool mask_center = false;
    double mask_radius = 0.5; // arcsec
    std::string masks;
    read_args(argc-1, argv+1, arg_list(mask_center, masks, mask_radius));

    vec1d ra, dec, size;
    if (!masks.empty()) {
        ascii::read_table(masks, ascii::find_skip(masks), _, ra, dec, size);
    }

    auto ksigma = [](vec1d data) {
        double v = median(data);
        double m = 1.48*median(abs(data - v));
        vec1u idg = where(abs(data - v) < 7*m);
        return mean(data[idg]);
    };

    for (auto oname : files) {
        std::string newfile = file::get_basename(oname);
        file::copy(oname, newfile);
        fits::image fimg(newfile);
        for (uint_t i : range(1, fimg.hdu_count())) {
            fimg.reach_hdu(i);
            if (fimg.axis_count() != 3) continue;

            vec3d cube;
            fimg.read(cube);

            uint_t ny = cube.dims[1];
            uint_t nx = cube.dims[2];

            vec2b mask = replicate(true, ny, nx);

            // Mask nearby sources from the provided catalog (if any)
            if (!ra.empty()) {
                astro::wcs w(fimg.read_header());
                vec1d x, y;
                astro::ad2xy(w, ra, dec, x, y);
                x -= 1.0; y -= 1.0;
                double aspix = 1.0;
                if (!astro::get_pixel_size(w, aspix)) {
                    error("could not read pixel size from cube");
                    return 1;
                }

                vec1d r = size/aspix;

                vec2d ix = generate_img(mask.dims, [](int_t,    int_t tx) { return tx; });
                vec2d iy = generate_img(mask.dims, [](int_t ty, int_t)    { return ty; });

                for (uint_t s : range(ra)) {
                    mask = mask && sqr(x[s] - ix) + sqr(y[s] - iy) > sqr(r[s]);
                }
            } else if (mask_center) {
                astro::wcs w(fimg.read_header());
                double aspix = 1.0;
                if (!astro::get_pixel_size(w, aspix)) {
                    error("could not read pixel size from cube");
                    return 1;
                }

                vec2d ix = generate_img(mask.dims, [](int_t,    int_t tx) { return tx; });
                vec2d iy = generate_img(mask.dims, [](int_t ty, int_t)    { return ty; });

                mask = mask && sqr(nx/2 - ix) + sqr(ny/2 - iy) > sqr(mask_radius/aspix);
            }

            // Mask borders
            mask(0,_) = mask(ny-1,_) = mask(_,0) = mask(_,nx-1) = false;

            // Subtract whole IFU
            vec1u idg = where(mask);
            for (uint_t l : range(cube.dims[0])) {
                cube(l,_,_) -= ksigma(cube(l,_,_)[idg]);
            }

            fimg.update(cube);
        }
    }

    return 0;
}
<|endoftext|>


<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 2000-2002 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xalan" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

#include "ICUBridgeCollationCompareFunctorImpl.hpp"
#include "ICUBridge.hpp"

#include <algorithm>
#include <cstdlib>

#include <Include/XalanAutoPtr.hpp>

#include <PlatformSupport/DOMStringHelper.hpp>
#include <PlatformSupport/XalanUnicode.hpp>

XALAN_CPP_NAMESPACE_BEGIN

const StylesheetExecutionContextDefault::DefaultCollationCompareFunctor		ICUBridgeCollationCompareFunctorImpl::s_defaultFunctor;

inline ICUBridgeCollationCompareFunctorImpl::CollatorType*
createCollator(
			UErrorCode&			theStatus,
			const Locale&		theLocale,
			XalanDOMString*		theLocaleName = 0)
{
	typedef ICUBridgeCollationCompareFunctorImpl::CollatorType	CollatorType;

	if (theLocaleName != 0)
	{
		*theLocaleName = theLocale.getName();

		// Replace _ with -, since that's what xml:lang specifies...
		XalanDOMString::size_type	theIndex;

		while((theIndex = indexOf(*theLocaleName, XalanUnicode::charLowLine)) != theLocaleName->length())
		{
			(*theLocaleName)[theIndex] = XalanUnicode::charHyphenMinus;
		}
	}

	return CollatorType::createInstance(theLocale, theStatus);
}

inline ICUBridgeCollationCompareFunctorImpl::CollatorType*
createCollator(
			UErrorCode&			theStatus,
			XalanDOMString*		theLocaleName = 0)
{
	const char*		theLang =
#if defined(XALAN_STRICT_ANSI_HEADERS)
			std::getenv("LANG");
#else
			getenv("LANG");
#endif

	if (theLang == 0)
	{
#if defined(XALAN_ICU_DEFAULT_LOCALE_PROBLEM)
		return createCollator(theStatus, Locale::US, theLocaleName);
#else
		return createCollator(theStatus, Locale::getDefault(), theLocaleName);
#endif
	}
	else
	{
		return createCollator(theStatus, Locale(theLang), theLocaleName);
	}
}

ICUBridgeCollationCompareFunctorImpl::ICUBridgeCollationCompareFunctorImpl(bool		fCacheCollators) :
	m_isValid(false),
	m_defaultCollator(0),
	m_defaultCollatorLocaleName(),
	m_cacheCollators(fCacheCollators),
	m_collatorCache()
{
	UErrorCode	theStatus = U_ZERO_ERROR;

	m_defaultCollator = createCollator(theStatus, &m_defaultCollatorLocaleName);

	if (U_SUCCESS(theStatus))
	{
		m_isValid = true;
	}
}

ICUBridgeCollationCompareFunctorImpl::~ICUBridgeCollationCompareFunctorImpl()
{
#if !defined(XALAN_NO_NAMESPACES)
	using std::for_each;
#endif

	delete m_defaultCollator;

	for_each(
			m_collatorCache.begin(),
			m_collatorCache.end(),
			CollationCacheStruct::CollatorDeleteFunctor());
}

int
ICUBridgeCollationCompareFunctorImpl::doCompare(
			const CollatorType&		theCollator,
			const XalanDOMChar*		theLHS,
			const XalanDOMChar*		theRHS) const
{
#if defined(XALAN_USE_WCHAR_CAST_HACK)
	return theCollator.compare(
				(const wchar_t*)theLHS,
				length(theLHS),
				(const wchar_t*)theRHS,
				length(theRHS));
#else
	return theCollator.compare(
				theLHS,
				length(theLHS),
				theRHS,
				length(theRHS));
#endif
}

inline UColAttributeValue
caseOrderConvert(ICUBridgeCollationCompareFunctorImpl::eCaseOrder	theCaseOrder)
{
	switch(theCaseOrder)
	{
	case StylesheetExecutionContext::eLowerFirst:
		return UCOL_LOWER_FIRST;
		break;

	case StylesheetExecutionContext::eUpperFirst:
		return UCOL_UPPER_FIRST;
		break;

	case StylesheetExecutionContext::eDefault:
		break;

	default:
		assert(false);
		break;
	}

	return UCOL_DEFAULT;
}

int
ICUBridgeCollationCompareFunctorImpl::doDefaultCompare(
			const XalanDOMChar*		theLHS,
			const XalanDOMChar*		theRHS) const
{
	if (isValid() == false)
	{
		return s_defaultFunctor(theLHS, theRHS, StylesheetExecutionContext::eDefault);
	}
	else
	{
		assert(m_defaultCollator != 0);

		return doCompare(*m_defaultCollator, theLHS, theRHS);
	}
}

inline ICUBridgeCollationCompareFunctorImpl::CollatorType*
createCollator(
			const XalanDOMChar*		theLocale,
			UErrorCode&				theStatus)
{
	assert(theLocale != 0);

	const XalanDOMString::size_type		theLength = length(theLocale);

	if (theLength >= ULOC_FULLNAME_CAPACITY)
	{
		theStatus = U_ILLEGAL_ARGUMENT_ERROR;

		return 0;
	}
	else
	{
#if defined(XALAN_NON_ASCII_PLATFORM)
		CharVectorType	theVector;

		TranscodeToLocalCodePage(theLocale, theVector, true);

		const char* const	theBuffer = c_str(theVector);
#else
		char	theBuffer[ULOC_FULLNAME_CAPACITY];

		// Since language names must be ASCII, this
		// is the cheapest way to "transcode"...
		for (unsigned int i = 0; i <= theLength; ++i)
		{
			theBuffer[i] = char(theLocale[i]);
		}
#endif
		return ICUBridgeCollationCompareFunctorImpl::CollatorType::createInstance(
					Locale::createFromName(theBuffer),
					theStatus);
	}
}

int
ICUBridgeCollationCompareFunctorImpl::doCompare(
			const XalanDOMChar*		theLHS,
			const XalanDOMChar*		theRHS,
			const XalanDOMChar*		theLocale,
			eCaseOrder				theCaseOrder) const
{
	UErrorCode	theStatus = U_ZERO_ERROR;

	XalanAutoPtr<CollatorType>	theCollator(createCollator(theLocale, theStatus));

	if (U_SUCCESS(theStatus))
	{
		assert(theCollator.get() != 0);

		return doCompare(
				*theCollator.get(),
				theLHS,
				theRHS,
				theCaseOrder);
	}
	else
	{
		return s_defaultFunctor(theLHS, theRHS, theCaseOrder);
	}
}

int
ICUBridgeCollationCompareFunctorImpl::doCompareCached(
			const XalanDOMChar*		theLHS,
			const XalanDOMChar*		theRHS,
			const XalanDOMChar*		theLocale,
			eCaseOrder				theCaseOrder) const
{
	CollatorType*	theCollator = getCachedCollator(theLocale);

	if (theCollator != 0)
	{
		return doCompare(*theCollator, theLHS, theRHS, theCaseOrder);
	}
	else
	{
		UErrorCode	theStatus = U_ZERO_ERROR;

		XalanAutoPtr<CollatorType>	theCollatorGuard(createCollator(theLocale, theStatus));

		if (U_SUCCESS(theStatus))
		{
			assert(theCollatorGuard.get() != 0);

			// OK, there was no error, so cache the instance...
			cacheCollator(theCollatorGuard.get(), theLocale);

			// Release the collator, since it's in the cache and
			// will be controlled by the cache...
			theCollator = theCollatorGuard.release();

			return doCompare(
					*theCollator,
					theLHS,
					theRHS,
					theCaseOrder);
		}
		else
		{
			return s_defaultFunctor(theLHS, theRHS, theCaseOrder);
		}
	}
}

int
ICUBridgeCollationCompareFunctorImpl::doCompare(
			CollatorType&			theCollator,
			const XalanDOMChar*		theLHS,
			const XalanDOMChar*		theRHS,
			eCaseOrder				theCaseOrder) const
{
	UErrorCode	theStatus = U_ZERO_ERROR;

	theCollator.setAttribute(
				UCOL_CASE_FIRST,
				caseOrderConvert(theCaseOrder),
				theStatus);

#if defined(XALAN_USE_WCHAR_CAST_HACK)
	return theCollator.compare(
					(const wchar_t*)theLHS,
					length(theLHS),
					(const wchar_t*)theRHS,
					length(theRHS));
#else
	return theCollator.compare(
					theLHS,
					length(theLHS),
					theRHS,
					length(theRHS));
#endif
}

int
ICUBridgeCollationCompareFunctorImpl::operator()(
			const XalanDOMChar*		theLHS,
			const XalanDOMChar*		theRHS,
			eCaseOrder				theCaseOrder) const
{
	if (theCaseOrder == StylesheetExecutionContext::eDefault)
	{
		return doDefaultCompare(theLHS, theRHS);
	}
	else
	{
		return doCompare(
				theLHS,
				theRHS,
				c_wstr(m_defaultCollatorLocaleName),
				theCaseOrder);
	}
}

int
ICUBridgeCollationCompareFunctorImpl::operator()(
			const XalanDOMChar*		theLHS,
			const XalanDOMChar*		theRHS,
			const XalanDOMChar*		theLocale,
			eCaseOrder				theCaseOrder) const
{
	if (theCaseOrder == StylesheetExecutionContext::eDefault &&
		XalanDOMString::equals(m_defaultCollatorLocaleName, theLocale) == true)
	{
		return doDefaultCompare(theLHS, theRHS);
	}
	else if (m_cacheCollators == true)
	{
		return doCompareCached(theLHS, theRHS, theLocale, theCaseOrder);
	}
	else
	{
		return doCompare(theLHS, theRHS, theLocale, theCaseOrder);
	};
}

ICUBridgeCollationCompareFunctorImpl::CollatorType*
ICUBridgeCollationCompareFunctorImpl::getCachedCollator(const XalanDOMChar*		theLocale) const
{
#if !defined(XALAN_NO_NAMESPACES)
	using std::find_if;
#endif

	CollatorCacheListType&		theNonConstCache =
#if defined(XALAN_NO_MUTABLE)
		(CollatorCacheListType*)m_collatorCache;
#else
		m_collatorCache;
#endif

	CollatorCacheListType::iterator	i =
		find_if(
			theNonConstCache.begin(),
			theNonConstCache.end(),
			CollationCacheStruct::CollatorFindFunctor(theLocale));

	if (i == theNonConstCache.end())
	{
		return 0;
	}
	else
	{
		// Let's do a quick check to see if we found the first entry.
		// If so, we don't have to update the cache, so just return the
		// appropriate value...
		const CollatorCacheListType::iterator	theBegin =
			theNonConstCache.begin();

		if (i == theBegin)
		{
			return (*i).m_collator;
		}
		else
		{
			// Save the collator, because splice() may invalidate
			// i.
			CollatorType* const		theCollator = (*i).m_collator;

			// Move the entry to the beginning the cache
			theNonConstCache.splice(theBegin, theNonConstCache, i);

			return theCollator;
		}
	}
}

void
ICUBridgeCollationCompareFunctorImpl::cacheCollator(
			CollatorType*			theCollator,
			const XalanDOMChar*		theLocale) const
{
	assert(theCollator != 0);
	assert(theLocale != 0);

	CollatorCacheListType&		theNonConstCache =
#if defined(XALAN_NO_MUTABLE)
		(CollatorCacheListType*)m_collatorCache;
#else
		m_collatorCache;
#endif

	// Is the cache full?
	if (theNonConstCache.size() == eCacheMax)
	{
		// Yes, so guard the collator instance, in case pop_back() throws...
		XalanAutoPtr<CollatorType>	theCollatorGuard(theNonConstCache.back().m_collator);

		theNonConstCache.pop_back();
	}

	theNonConstCache.push_front(CollatorCacheListType::value_type());

	CollatorCacheListType::value_type&		theEntry =
		theNonConstCache.front();

	// Set the locale first, since that might throw an exception...
	theEntry.m_locale = theLocale;

	theEntry.m_collator = theCollator;
}

XALAN_CPP_NAMESPACE_END
<commit_msg>New ifdef for 64-bit AIX 5.1.<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 2000-2002 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xalan" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

#include "ICUBridgeCollationCompareFunctorImpl.hpp"
#include "ICUBridge.hpp"

#include <algorithm>
#include <cstdlib>

#include <Include/XalanAutoPtr.hpp>

#include <PlatformSupport/DOMStringHelper.hpp>
#include <PlatformSupport/XalanUnicode.hpp>

XALAN_CPP_NAMESPACE_BEGIN

const StylesheetExecutionContextDefault::DefaultCollationCompareFunctor		ICUBridgeCollationCompareFunctorImpl::s_defaultFunctor;

inline ICUBridgeCollationCompareFunctorImpl::CollatorType*
createCollator(
			UErrorCode&			theStatus,
			const Locale&		theLocale,
			XalanDOMString*		theLocaleName = 0)
{
	typedef ICUBridgeCollationCompareFunctorImpl::CollatorType	CollatorType;

	if (theLocaleName != 0)
	{
		*theLocaleName = theLocale.getName();

		// Replace _ with -, since that's what xml:lang specifies...
		XalanDOMString::size_type	theIndex;

		while((theIndex = indexOf(*theLocaleName, XalanUnicode::charLowLine)) != theLocaleName->length())
		{
			(*theLocaleName)[theIndex] = XalanUnicode::charHyphenMinus;
		}
	}

	return CollatorType::createInstance(theLocale, theStatus);
}

inline ICUBridgeCollationCompareFunctorImpl::CollatorType*
createCollator(
			UErrorCode&			theStatus,
			XalanDOMString*		theLocaleName = 0)
{
	const char*		theLang =
#if defined(XALAN_STRICT_ANSI_HEADERS)
			std::getenv("LANG");
#else
			getenv("LANG");
#endif

	if (theLang == 0)
	{
#if defined(XALAN_ICU_DEFAULT_LOCALE_PROBLEM)
		return createCollator(theStatus, Locale::US, theLocaleName);
#else
		return createCollator(theStatus, Locale::getDefault(), theLocaleName);
#endif
	}
	else
	{
		return createCollator(theStatus, Locale(theLang), theLocaleName);
	}
}

ICUBridgeCollationCompareFunctorImpl::ICUBridgeCollationCompareFunctorImpl(bool		fCacheCollators) :
	m_isValid(false),
	m_defaultCollator(0),
	m_defaultCollatorLocaleName(),
	m_cacheCollators(fCacheCollators),
	m_collatorCache()
{
	UErrorCode	theStatus = U_ZERO_ERROR;

	m_defaultCollator = createCollator(theStatus, &m_defaultCollatorLocaleName);

	if (U_SUCCESS(theStatus))
	{
		m_isValid = true;
	}
}

ICUBridgeCollationCompareFunctorImpl::~ICUBridgeCollationCompareFunctorImpl()
{
#if !defined(XALAN_NO_NAMESPACES)
	using std::for_each;
#endif

	delete m_defaultCollator;

	for_each(
			m_collatorCache.begin(),
			m_collatorCache.end(),
			CollationCacheStruct::CollatorDeleteFunctor());
}

int
ICUBridgeCollationCompareFunctorImpl::doCompare(
			const CollatorType&		theCollator,
			const XalanDOMChar*		theLHS,
			const XalanDOMChar*		theRHS) const
{
#if defined(XALAN_USE_WCHAR_CAST_HACK) && defined(U_WCHAR_IS_UTF16)
	return theCollator.compare(
				(const wchar_t*)theLHS,
				length(theLHS),
				(const wchar_t*)theRHS,
				length(theRHS));
#else
	return theCollator.compare(
				theLHS,
				length(theLHS),
				theRHS,
				length(theRHS));
#endif
}

inline UColAttributeValue
caseOrderConvert(ICUBridgeCollationCompareFunctorImpl::eCaseOrder	theCaseOrder)
{
	switch(theCaseOrder)
	{
	case StylesheetExecutionContext::eLowerFirst:
		return UCOL_LOWER_FIRST;
		break;

	case StylesheetExecutionContext::eUpperFirst:
		return UCOL_UPPER_FIRST;
		break;

	case StylesheetExecutionContext::eDefault:
		break;

	default:
		assert(false);
		break;
	}

	return UCOL_DEFAULT;
}

int
ICUBridgeCollationCompareFunctorImpl::doDefaultCompare(
			const XalanDOMChar*		theLHS,
			const XalanDOMChar*		theRHS) const
{
	if (isValid() == false)
	{
		return s_defaultFunctor(theLHS, theRHS, StylesheetExecutionContext::eDefault);
	}
	else
	{
		assert(m_defaultCollator != 0);

		return doCompare(*m_defaultCollator, theLHS, theRHS);
	}
}

inline ICUBridgeCollationCompareFunctorImpl::CollatorType*
createCollator(
			const XalanDOMChar*		theLocale,
			UErrorCode&				theStatus)
{
	assert(theLocale != 0);

	const XalanDOMString::size_type		theLength = length(theLocale);

	if (theLength >= ULOC_FULLNAME_CAPACITY)
	{
		theStatus = U_ILLEGAL_ARGUMENT_ERROR;

		return 0;
	}
	else
	{
#if defined(XALAN_NON_ASCII_PLATFORM)
		CharVectorType	theVector;

		TranscodeToLocalCodePage(theLocale, theVector, true);

		const char* const	theBuffer = c_str(theVector);
#else
		char	theBuffer[ULOC_FULLNAME_CAPACITY];

		// Since language names must be ASCII, this
		// is the cheapest way to "transcode"...
		for (unsigned int i = 0; i <= theLength; ++i)
		{
			theBuffer[i] = char(theLocale[i]);
		}
#endif
		return ICUBridgeCollationCompareFunctorImpl::CollatorType::createInstance(
					Locale::createFromName(theBuffer),
					theStatus);
	}
}

int
ICUBridgeCollationCompareFunctorImpl::doCompare(
			const XalanDOMChar*		theLHS,
			const XalanDOMChar*		theRHS,
			const XalanDOMChar*		theLocale,
			eCaseOrder				theCaseOrder) const
{
	UErrorCode	theStatus = U_ZERO_ERROR;

	XalanAutoPtr<CollatorType>	theCollator(createCollator(theLocale, theStatus));

	if (U_SUCCESS(theStatus))
	{
		assert(theCollator.get() != 0);

		return doCompare(
				*theCollator.get(),
				theLHS,
				theRHS,
				theCaseOrder);
	}
	else
	{
		return s_defaultFunctor(theLHS, theRHS, theCaseOrder);
	}
}

int
ICUBridgeCollationCompareFunctorImpl::doCompareCached(
			const XalanDOMChar*		theLHS,
			const XalanDOMChar*		theRHS,
			const XalanDOMChar*		theLocale,
			eCaseOrder				theCaseOrder) const
{
	CollatorType*	theCollator = getCachedCollator(theLocale);

	if (theCollator != 0)
	{
		return doCompare(*theCollator, theLHS, theRHS, theCaseOrder);
	}
	else
	{
		UErrorCode	theStatus = U_ZERO_ERROR;

		XalanAutoPtr<CollatorType>	theCollatorGuard(createCollator(theLocale, theStatus));

		if (U_SUCCESS(theStatus))
		{
			assert(theCollatorGuard.get() != 0);

			// OK, there was no error, so cache the instance...
			cacheCollator(theCollatorGuard.get(), theLocale);

			// Release the collator, since it's in the cache and
			// will be controlled by the cache...
			theCollator = theCollatorGuard.release();

			return doCompare(
					*theCollator,
					theLHS,
					theRHS,
					theCaseOrder);
		}
		else
		{
			return s_defaultFunctor(theLHS, theRHS, theCaseOrder);
		}
	}
}

int
ICUBridgeCollationCompareFunctorImpl::doCompare(
			CollatorType&			theCollator,
			const XalanDOMChar*		theLHS,
			const XalanDOMChar*		theRHS,
			eCaseOrder				theCaseOrder) const
{
	UErrorCode	theStatus = U_ZERO_ERROR;

	theCollator.setAttribute(
				UCOL_CASE_FIRST,
				caseOrderConvert(theCaseOrder),
				theStatus);

#if defined(XALAN_USE_WCHAR_CAST_HACK) && defined(U_WCHAR_IS_UTF16)
	return theCollator.compare(
					(const wchar_t*)theLHS,
					length(theLHS),
					(const wchar_t*)theRHS,
					length(theRHS));
#else
	return theCollator.compare(
					theLHS,
					length(theLHS),
					theRHS,
					length(theRHS));
#endif
}

int
ICUBridgeCollationCompareFunctorImpl::operator()(
			const XalanDOMChar*		theLHS,
			const XalanDOMChar*		theRHS,
			eCaseOrder				theCaseOrder) const
{
	if (theCaseOrder == StylesheetExecutionContext::eDefault)
	{
		return doDefaultCompare(theLHS, theRHS);
	}
	else
	{
		return doCompare(
				theLHS,
				theRHS,
				c_wstr(m_defaultCollatorLocaleName),
				theCaseOrder);
	}
}

int
ICUBridgeCollationCompareFunctorImpl::operator()(
			const XalanDOMChar*		theLHS,
			const XalanDOMChar*		theRHS,
			const XalanDOMChar*		theLocale,
			eCaseOrder				theCaseOrder) const
{
	if (theCaseOrder == StylesheetExecutionContext::eDefault &&
		XalanDOMString::equals(m_defaultCollatorLocaleName, theLocale) == true)
	{
		return doDefaultCompare(theLHS, theRHS);
	}
	else if (m_cacheCollators == true)
	{
		return doCompareCached(theLHS, theRHS, theLocale, theCaseOrder);
	}
	else
	{
		return doCompare(theLHS, theRHS, theLocale, theCaseOrder);
	};
}

ICUBridgeCollationCompareFunctorImpl::CollatorType*
ICUBridgeCollationCompareFunctorImpl::getCachedCollator(const XalanDOMChar*		theLocale) const
{
#if !defined(XALAN_NO_NAMESPACES)
	using std::find_if;
#endif

	CollatorCacheListType&		theNonConstCache =
#if defined(XALAN_NO_MUTABLE)
		(CollatorCacheListType*)m_collatorCache;
#else
		m_collatorCache;
#endif

	CollatorCacheListType::iterator	i =
		find_if(
			theNonConstCache.begin(),
			theNonConstCache.end(),
			CollationCacheStruct::CollatorFindFunctor(theLocale));

	if (i == theNonConstCache.end())
	{
		return 0;
	}
	else
	{
		// Let's do a quick check to see if we found the first entry.
		// If so, we don't have to update the cache, so just return the
		// appropriate value...
		const CollatorCacheListType::iterator	theBegin =
			theNonConstCache.begin();

		if (i == theBegin)
		{
			return (*i).m_collator;
		}
		else
		{
			// Save the collator, because splice() may invalidate
			// i.
			CollatorType* const		theCollator = (*i).m_collator;

			// Move the entry to the beginning the cache
			theNonConstCache.splice(theBegin, theNonConstCache, i);

			return theCollator;
		}
	}
}

void
ICUBridgeCollationCompareFunctorImpl::cacheCollator(
			CollatorType*			theCollator,
			const XalanDOMChar*		theLocale) const
{
	assert(theCollator != 0);
	assert(theLocale != 0);

	CollatorCacheListType&		theNonConstCache =
#if defined(XALAN_NO_MUTABLE)
		(CollatorCacheListType*)m_collatorCache;
#else
		m_collatorCache;
#endif

	// Is the cache full?
	if (theNonConstCache.size() == eCacheMax)
	{
		// Yes, so guard the collator instance, in case pop_back() throws...
		XalanAutoPtr<CollatorType>	theCollatorGuard(theNonConstCache.back().m_collator);

		theNonConstCache.pop_back();
	}

	theNonConstCache.push_front(CollatorCacheListType::value_type());

	CollatorCacheListType::value_type&		theEntry =
		theNonConstCache.front();

	// Set the locale first, since that might throw an exception...
	theEntry.m_locale = theLocale;

	theEntry.m_collator = theCollator;
}

XALAN_CPP_NAMESPACE_END
<|endoftext|>


<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 2000-2002 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xalan" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

#if !defined(ICUBRIDGE_COLLATIONCOMPAREFUNCTORIMPL_GUARD_1357924680)
#define ICUBRIDGE_COLLATIONCOMPAREFUNCTORIMPL_GUARD_1357924680

#include <ICUBridge/ICUBridgeDefinitions.hpp>

#include <list>

#include <XSLT/StylesheetExecutionContextDefault.hpp>

#include <unicode/coll.h>

XALAN_CPP_NAMESPACE_BEGIN

class XALAN_ICUBRIDGE_EXPORT ICUBridgeCollationCompareFunctorImpl : public StylesheetExecutionContextDefault::CollationCompareFunctor
{
public:

	typedef StylesheetExecutionContextDefault::eCaseOrder	eCaseOrder;

	/**
	 * Constructor.
	 *
	 * @param fCacheCollators If true, the instance will cache collators.  This is not thread-safe, so each thread must have its own instance.
	 */
	ICUBridgeCollationCompareFunctorImpl(bool	fCacheCollators = false);

	~ICUBridgeCollationCompareFunctorImpl();

	int
	operator()(
			const XalanDOMChar*		theLHS,
			const XalanDOMChar*		theRHS,
			eCaseOrder				theCaseOrder = StylesheetExecutionContextDefault::eDefault) const;

	int
	operator()(
			const XalanDOMChar*		theLHS,
			const XalanDOMChar*		theRHS,
			const XalanDOMChar*		theLocale,
			eCaseOrder				theCaseOrder = StylesheetExecutionContextDefault::eDefault) const;

	bool
	isValid() const
	{
		return m_isValid;
	}

#if defined(XALAN_HAS_CPP_NAMESPACE)
	typedef U_ICU_NAMESPACE::Collator	CollatorType;
#else
	typedef Collator					CollatorType;
#endif

	struct CollationCacheStruct
	{
		CollationCacheStruct(
				const XalanDOMString&	theLocale,
				CollatorType*			theCollator) :
			m_locale(theLocale),
			m_collator(theCollator)
		{
		}

		CollationCacheStruct() :
			m_locale(),
			m_collator(0)
		{
		}

		void
		swap(CollationCacheStruct&	theOther)
		{
			m_locale.swap(theOther.m_locale);

			CollatorType* const		theTemp = m_collator;

			m_collator = theOther.m_collator;

			theOther.m_collator = theTemp;
		}

		XalanDOMString	m_locale;

		CollatorType*	m_collator;

		struct CollatorDeleteFunctor
		{
			void
			operator()(CollationCacheStruct&	theStruct) const
			{
				delete theStruct.m_collator;
			}
		};

		struct CollatorFindFunctor
		{
			CollatorFindFunctor(const XalanDOMChar*	theLocale) :
				m_locale(theLocale)
			{
			}

			bool
			operator()(CollationCacheStruct&	theStruct) const
			{
				return XalanDOMString::equals(theStruct.m_locale ,m_locale);
			}

			const XalanDOMChar* const	m_locale;
		};
	};

#if defined(XALAN_NO_STD_NAMESPACE)
	typedef list<CollationCacheStruct>			CollatorCacheListType;
#else
	typedef std::list<CollationCacheStruct>		CollatorCacheListType;
#endif

	enum { eCacheMax = 10 };

private:

	int
	doDefaultCompare(
			const XalanDOMChar*		theLHS,
			const XalanDOMChar*		theRHS) const;

	int
	doCompare(
			const XalanDOMChar*		theLHS,
			const XalanDOMChar*		theRHS,
			const XalanDOMChar*		theLocale,
			eCaseOrder				theCaseOrder) const;

	int
	doCompareCached(
			const XalanDOMChar*		theLHS,
			const XalanDOMChar*		theRHS,
			const XalanDOMChar*		theLocale,
			eCaseOrder				theCaseOrder) const;

	int
	doCompare(
			const CollatorType&		theCollator,
			const XalanDOMChar*		theLHS,
			const XalanDOMChar*		theRHS) const;

	int
	doCompare(
			CollatorType&			theCollator,
			const XalanDOMChar*		theLHS,
			const XalanDOMChar*		theRHS,
			eCaseOrder				theCaseOrder) const;

	CollatorType*
	getCachedCollator(const XalanDOMChar*	theLocale) const;

	void
	cacheCollator(
			CollatorType*			theCollator,
			const XalanDOMChar*		theLocale) const;

	// Data members...
	bool							m_isValid;

	CollatorType*					m_defaultCollator;

	XalanDOMString					m_defaultCollatorLocaleName;

	bool							m_cacheCollators;

	mutable CollatorCacheListType	m_collatorCache;

	const static StylesheetExecutionContextDefault::DefaultCollationCompareFunctor	s_defaultFunctor;
};

XALAN_CPP_NAMESPACE_END

#endif	// ICUBRIDGE_COLLATIONCOMPAREFUNCTORIMPL_GUARD_1357924680
<commit_msg>Added operators for brain-dead compilers.<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 2000-2002 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xalan" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

#if !defined(ICUBRIDGE_COLLATIONCOMPAREFUNCTORIMPL_GUARD_1357924680)
#define ICUBRIDGE_COLLATIONCOMPAREFUNCTORIMPL_GUARD_1357924680

#include <ICUBridge/ICUBridgeDefinitions.hpp>

#include <list>

#include <XSLT/StylesheetExecutionContextDefault.hpp>

#include <unicode/coll.h>

XALAN_CPP_NAMESPACE_BEGIN

class XALAN_ICUBRIDGE_EXPORT ICUBridgeCollationCompareFunctorImpl : public StylesheetExecutionContextDefault::CollationCompareFunctor
{
public:

	typedef StylesheetExecutionContextDefault::eCaseOrder	eCaseOrder;

	/**
	 * Constructor.
	 *
	 * @param fCacheCollators If true, the instance will cache collators.  This is not thread-safe, so each thread must have its own instance.
	 */
	ICUBridgeCollationCompareFunctorImpl(bool	fCacheCollators = false);

	~ICUBridgeCollationCompareFunctorImpl();

	int
	operator()(
			const XalanDOMChar*		theLHS,
			const XalanDOMChar*		theRHS,
			eCaseOrder				theCaseOrder = StylesheetExecutionContextDefault::eDefault) const;

	int
	operator()(
			const XalanDOMChar*		theLHS,
			const XalanDOMChar*		theRHS,
			const XalanDOMChar*		theLocale,
			eCaseOrder				theCaseOrder = StylesheetExecutionContextDefault::eDefault) const;

	bool
	isValid() const
	{
		return m_isValid;
	}

#if defined(XALAN_HAS_CPP_NAMESPACE)
	typedef U_ICU_NAMESPACE::Collator	CollatorType;
#else
	typedef Collator					CollatorType;
#endif

	struct CollationCacheStruct
	{
		CollationCacheStruct(
				const XalanDOMString&	theLocale,
				CollatorType*			theCollator) :
			m_locale(theLocale),
			m_collator(theCollator)
		{
		}

		CollationCacheStruct() :
			m_locale(),
			m_collator(0)
		{
		}

		void
		swap(CollationCacheStruct&	theOther)
		{
			m_locale.swap(theOther.m_locale);

			CollatorType* const		theTemp = m_collator;

			m_collator = theOther.m_collator;

			theOther.m_collator = theTemp;
		}

#if defined(XALAN_NO_SELECTIVE_TEMPLATE_INSTANTIATION)
		bool
		operator<(const CollationCacheStruct&  theRHS) const
		{
			return this < &theRHS;
		}

		bool
		operator==(const CollationCacheStruct&	theRHS) const
		{
			return this == &theRHS;
		}
#endif

		XalanDOMString	m_locale;

		CollatorType*	m_collator;

		struct CollatorDeleteFunctor
		{
			void
			operator()(CollationCacheStruct&	theStruct) const
			{
				delete theStruct.m_collator;
			}
		};

		struct CollatorFindFunctor
		{
			CollatorFindFunctor(const XalanDOMChar*	theLocale) :
				m_locale(theLocale)
			{
			}

			bool
			operator()(CollationCacheStruct&	theStruct) const
			{
				return XalanDOMString::equals(theStruct.m_locale ,m_locale);
			}

			const XalanDOMChar* const	m_locale;
		};
	};

#if defined(XALAN_NO_STD_NAMESPACE)
	typedef list<CollationCacheStruct>			CollatorCacheListType;
#else
	typedef std::list<CollationCacheStruct>		CollatorCacheListType;
#endif

	enum { eCacheMax = 10 };

private:

	int
	doDefaultCompare(
			const XalanDOMChar*		theLHS,
			const XalanDOMChar*		theRHS) const;

	int
	doCompare(
			const XalanDOMChar*		theLHS,
			const XalanDOMChar*		theRHS,
			const XalanDOMChar*		theLocale,
			eCaseOrder				theCaseOrder) const;

	int
	doCompareCached(
			const XalanDOMChar*		theLHS,
			const XalanDOMChar*		theRHS,
			const XalanDOMChar*		theLocale,
			eCaseOrder				theCaseOrder) const;

	int
	doCompare(
			const CollatorType&		theCollator,
			const XalanDOMChar*		theLHS,
			const XalanDOMChar*		theRHS) const;

	int
	doCompare(
			CollatorType&			theCollator,
			const XalanDOMChar*		theLHS,
			const XalanDOMChar*		theRHS,
			eCaseOrder				theCaseOrder) const;

	CollatorType*
	getCachedCollator(const XalanDOMChar*	theLocale) const;

	void
	cacheCollator(
			CollatorType*			theCollator,
			const XalanDOMChar*		theLocale) const;

	// Data members...
	bool							m_isValid;

	CollatorType*					m_defaultCollator;

	XalanDOMString					m_defaultCollatorLocaleName;

	bool							m_cacheCollators;

	mutable CollatorCacheListType	m_collatorCache;

	const static StylesheetExecutionContextDefault::DefaultCollationCompareFunctor	s_defaultFunctor;
};

XALAN_CPP_NAMESPACE_END

#endif	// ICUBRIDGE_COLLATIONCOMPAREFUNCTORIMPL_GUARD_1357924680
<|endoftext|>