DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Header

Mercurial (666b11c33fee)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "mozilla/dom/FallbackEncoding.h"

#include "mozilla/ArrayUtils.h"
#include "mozilla/Encoding.h"
#include "mozilla/intl/LocaleService.h"
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
#include "nsIObserverService.h"
#include "nsUConvPropertySearch.h"

using mozilla::intl::LocaleService;

namespace mozilla {
namespace dom {

struct EncodingProp {
  const char* const mKey;
  NotNull<const Encoding*> mValue;
};

template <int32_t N>
static NotNull<const Encoding*> SearchEncodingProp(
    const EncodingProp (&aProperties)[N], const nsACString& aKey) {
  const nsCString& flat = PromiseFlatCString(aKey);
  size_t index;
  if (!BinarySearchIf(
          aProperties, 0, ArrayLength(aProperties),
          [&flat](const EncodingProp& aProperty) {
            return flat.Compare(aProperty.mKey);
          },
          &index)) {
    return WINDOWS_1252_ENCODING;
  }
  return aProperties[index].mValue;
}

static const EncodingProp localesFallbacks[] = {
#include "localesfallbacks.properties.h"
};

static const EncodingProp domainsFallbacks[] = {
#include "domainsfallbacks.properties.h"
};

static constexpr nsUConvProp nonParticipatingDomains[] = {
#include "nonparticipatingdomains.properties.h"
};

NS_IMPL_ISUPPORTS(FallbackEncoding, nsIObserver)

StaticRefPtr<FallbackEncoding> FallbackEncoding::sInstance;

FallbackEncoding::FallbackEncoding() : mFallback(nullptr) {
  MOZ_ASSERT(!FallbackEncoding::sInstance, "Singleton already exists.");
}

NotNull<const Encoding*> FallbackEncoding::Get() {
  if (mFallback) {
    return WrapNotNull(mFallback);
  }

  nsAutoCString override;
  Preferences::GetCString("intl.charset.fallback.override", override);
  // Don't let the user break things by setting the override to unreasonable
  // values via about:config
  auto encoding = Encoding::ForLabel(override);
  if (!encoding || !encoding->IsAsciiCompatible() ||
      encoding == UTF_8_ENCODING) {
    mFallback = nullptr;
  } else {
    mFallback = encoding;
  }

  if (mFallback) {
    return WrapNotNull(mFallback);
  }

  nsAutoCString locale;
  LocaleService::GetInstance()->GetAppLocaleAsLangTag(locale);

  // Let's lower case the string just in case unofficial language packs
  // don't stick to conventions.
  ToLowerCase(locale);  // ASCII lowercasing with CString input!

  // Special case Traditional Chinese before throwing away stuff after the
  // language itself. Today we only ship zh-TW, but be defensive about
  // possible future values.
  if (locale.EqualsLiteral("zh-tw") || locale.EqualsLiteral("zh-hk") ||
      locale.EqualsLiteral("zh-mo") || locale.EqualsLiteral("zh-hant")) {
    mFallback = BIG5_ENCODING;
    return WrapNotNull(mFallback);
  }

  // Throw away regions and other variants to accommodate weird stuff seen
  // in telemetry--apparently unofficial language packs.
  int32_t index = locale.FindChar('-');
  if (index >= 0) {
    locale.Truncate(index);
  }

  auto fallback = SearchEncodingProp(localesFallbacks, locale);
  mFallback = fallback;

  return fallback;
}

NotNull<const Encoding*> FallbackEncoding::FromLocale() {
  MOZ_ASSERT(FallbackEncoding::sInstance,
             "Using uninitialized fallback cache.");
  return FallbackEncoding::sInstance->Get();
}

// PrefChangedFunc
void FallbackEncoding::PrefChanged(const char*, void*) {
  MOZ_ASSERT(FallbackEncoding::sInstance,
             "Pref callback called with null fallback cache.");
  FallbackEncoding::sInstance->Invalidate();
}

NS_IMETHODIMP
FallbackEncoding::Observe(nsISupports* aSubject, const char* aTopic,
                          const char16_t* aData) {
  MOZ_ASSERT(FallbackEncoding::sInstance,
             "Observe callback called with null fallback cache.");
  FallbackEncoding::sInstance->Invalidate();
  return NS_OK;
}

void FallbackEncoding::Initialize() {
  MOZ_ASSERT(!FallbackEncoding::sInstance,
             "Initializing pre-existing fallback cache.");
  FallbackEncoding::sInstance = new FallbackEncoding;
  Preferences::RegisterCallback(FallbackEncoding::PrefChanged,
                                "intl.charset.fallback.override");

  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
  if (obs) {
    obs->AddObserver(sInstance, "intl:requested-locales-changed", true);
  }
}

void FallbackEncoding::Shutdown() {
  MOZ_ASSERT(FallbackEncoding::sInstance,
             "Releasing non-existent fallback cache.");
  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
  if (obs) {
    obs->RemoveObserver(sInstance, "intl:requested-locales-changed");
  }
  FallbackEncoding::sInstance = nullptr;
}

bool FallbackEncoding::IsParticipatingTopLevelDomain(const nsACString& aTLD) {
  nsAutoCString dummy;
  return NS_FAILED(nsUConvPropertySearch::SearchPropertyValue(
      nonParticipatingDomains, ArrayLength(nonParticipatingDomains), aTLD,
      dummy));
}

NotNull<const Encoding*> FallbackEncoding::FromTopLevelDomain(
    const nsACString& aTLD) {
  return SearchEncodingProp(domainsFallbacks, aTLD);
}

}  // namespace dom
}  // namespace mozilla