1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/intl/unicharutil/src/nsEntityConverter.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,239 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nsEntityConverter.h" 1.10 +#include "nsLiteralString.h" 1.11 +#include "nsString.h" 1.12 +#include "mozilla/Services.h" 1.13 +#include "nsServiceManagerUtils.h" 1.14 +#include "nsCRT.h" 1.15 + 1.16 +// 1.17 +// implementation methods 1.18 +// 1.19 +nsEntityConverter::nsEntityConverter() : 1.20 + mVersionList(nullptr), 1.21 + mVersionListLength(0) 1.22 +{ 1.23 +} 1.24 + 1.25 +nsEntityConverter::~nsEntityConverter() 1.26 +{ 1.27 + if (mVersionList) 1.28 + delete [] mVersionList; 1.29 +} 1.30 + 1.31 +NS_IMETHODIMP 1.32 +nsEntityConverter::LoadVersionPropertyFile() 1.33 +{ 1.34 + NS_NAMED_LITERAL_CSTRING(url, "resource://gre/res/entityTables/htmlEntityVersions.properties"); 1.35 + 1.36 + nsCOMPtr<nsIStringBundleService> bundleService = 1.37 + mozilla::services::GetStringBundleService(); 1.38 + if (!bundleService) 1.39 + return NS_ERROR_FAILURE; 1.40 + 1.41 + nsCOMPtr<nsIStringBundle> entities; 1.42 + nsresult rv = bundleService->CreateBundle(url.get(), getter_AddRefs(entities)); 1.43 + if (NS_FAILED(rv)) return rv; 1.44 + 1.45 + nsresult result; 1.46 + 1.47 + nsAutoString key; 1.48 + nsXPIDLString value; 1.49 + rv = entities->GetStringFromName(MOZ_UTF16("length"), 1.50 + getter_Copies(value)); 1.51 + NS_ASSERTION(NS_SUCCEEDED(rv),"nsEntityConverter: malformed entity table\n"); 1.52 + if (NS_FAILED(rv)) return rv; 1.53 + 1.54 + mVersionListLength = nsAutoString(value).ToInteger(&result); 1.55 + NS_ASSERTION(32 >= mVersionListLength,"nsEntityConverter: malformed entity table\n"); 1.56 + if (32 < mVersionListLength) return NS_ERROR_FAILURE; 1.57 + 1.58 + mVersionList = new nsEntityVersionList[mVersionListLength]; 1.59 + if (!mVersionList) return NS_ERROR_OUT_OF_MEMORY; 1.60 + 1.61 + for (uint32_t i = 0; i < mVersionListLength && NS_SUCCEEDED(rv); i++) { 1.62 + key.SetLength(0); 1.63 + key.AppendInt(i+1, 10); 1.64 + rv = entities->GetStringFromName(key.get(), getter_Copies(value)); 1.65 + uint32_t len = value.Length(); 1.66 + if (kVERSION_STRING_LEN < len) return NS_ERROR_UNEXPECTED; 1.67 + 1.68 + memcpy(mVersionList[i].mEntityListName, value.get(), len*sizeof(char16_t)); 1.69 + mVersionList[i].mEntityListName[len] = 0; 1.70 + mVersionList[i].mVersion = (1 << i); 1.71 + } 1.72 + 1.73 + return NS_OK; 1.74 +} 1.75 + 1.76 +already_AddRefed<nsIStringBundle> 1.77 +nsEntityConverter::LoadEntityBundle(uint32_t version) 1.78 +{ 1.79 + nsAutoCString url(NS_LITERAL_CSTRING("resource://gre/res/entityTables/")); 1.80 + nsresult rv; 1.81 + 1.82 + nsCOMPtr<nsIStringBundleService> bundleService = 1.83 + do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv); 1.84 + NS_ENSURE_SUCCESS(rv, nullptr); 1.85 + 1.86 + const char16_t *versionName = GetVersionName(version); 1.87 + NS_ENSURE_TRUE(versionName, nullptr); 1.88 + 1.89 + // all property file names are ASCII, like "html40Latin1" so this is safe 1.90 + LossyAppendUTF16toASCII(versionName, url); 1.91 + url.Append(".properties"); 1.92 + 1.93 + nsCOMPtr<nsIStringBundle> bundle; 1.94 + rv = bundleService->CreateBundle(url.get(), getter_AddRefs(bundle)); 1.95 + NS_ENSURE_SUCCESS(rv, nullptr); 1.96 + 1.97 + return bundle.forget(); 1.98 +} 1.99 + 1.100 +const char16_t* 1.101 +nsEntityConverter:: GetVersionName(uint32_t versionNumber) 1.102 +{ 1.103 + for (uint32_t i = 0; i < mVersionListLength; i++) { 1.104 + if (versionNumber == mVersionList[i].mVersion) 1.105 + return mVersionList[i].mEntityListName; 1.106 + } 1.107 + 1.108 + return nullptr; 1.109 +} 1.110 + 1.111 +nsIStringBundle* 1.112 +nsEntityConverter:: GetVersionBundleInstance(uint32_t versionNumber) 1.113 +{ 1.114 + if (!mVersionList) { 1.115 + // load the property file which contains available version names 1.116 + // and generate a list of version/name pair 1.117 + if (NS_FAILED(LoadVersionPropertyFile())) 1.118 + return nullptr; 1.119 + } 1.120 + 1.121 + uint32_t i; 1.122 + for (i = 0; i < mVersionListLength; i++) { 1.123 + if (versionNumber == mVersionList[i].mVersion) { 1.124 + if (!mVersionList[i].mEntities) 1.125 + { // not loaded 1.126 + // load the property file 1.127 + mVersionList[i].mEntities = LoadEntityBundle(versionNumber); 1.128 + NS_ASSERTION(mVersionList[i].mEntities, "LoadEntityBundle failed"); 1.129 + } 1.130 + return mVersionList[i].mEntities.get(); 1.131 + } 1.132 + } 1.133 + 1.134 + return nullptr; 1.135 +} 1.136 + 1.137 + 1.138 +// 1.139 +// nsISupports methods 1.140 +// 1.141 +NS_IMPL_ISUPPORTS(nsEntityConverter,nsIEntityConverter) 1.142 + 1.143 + 1.144 +// 1.145 +// nsIEntityConverter 1.146 +// 1.147 +NS_IMETHODIMP 1.148 +nsEntityConverter::ConvertToEntity(char16_t character, uint32_t entityVersion, char **_retval) 1.149 +{ 1.150 + return ConvertUTF32ToEntity((uint32_t)character, entityVersion, _retval); 1.151 +} 1.152 + 1.153 +NS_IMETHODIMP 1.154 +nsEntityConverter::ConvertUTF32ToEntity(uint32_t character, uint32_t entityVersion, char **_retval) 1.155 +{ 1.156 + NS_ASSERTION(_retval, "null ptr- _retval"); 1.157 + if(nullptr == _retval) 1.158 + return NS_ERROR_NULL_POINTER; 1.159 + *_retval = nullptr; 1.160 + 1.161 + for (uint32_t mask = 1, mask2 = 0xFFFFFFFFL; (0!=(entityVersion & mask2)); mask<<=1, mask2<<=1) { 1.162 + if (0 == (entityVersion & mask)) 1.163 + continue; 1.164 + nsIStringBundle* entities = GetVersionBundleInstance(entityVersion & mask); 1.165 + NS_ASSERTION(entities, "Cannot get the property file"); 1.166 + 1.167 + if (!entities) 1.168 + continue; 1.169 + 1.170 + nsAutoString key(NS_LITERAL_STRING("entity.")); 1.171 + key.AppendInt(character,10); 1.172 + 1.173 + nsXPIDLString value; 1.174 + nsresult rv = entities->GetStringFromName(key.get(), getter_Copies(value)); 1.175 + if (NS_SUCCEEDED(rv)) { 1.176 + *_retval = ToNewCString(value); 1.177 + if(nullptr == *_retval) 1.178 + return NS_ERROR_OUT_OF_MEMORY; 1.179 + else 1.180 + return NS_OK; 1.181 + } 1.182 + } 1.183 + return NS_ERROR_ILLEGAL_VALUE; 1.184 +} 1.185 + 1.186 +NS_IMETHODIMP 1.187 +nsEntityConverter::ConvertToEntities(const char16_t *inString, uint32_t entityVersion, char16_t **_retval) 1.188 +{ 1.189 + NS_ENSURE_ARG_POINTER(inString); 1.190 + NS_ENSURE_ARG_POINTER(_retval); 1.191 + 1.192 + *_retval = nullptr; 1.193 + 1.194 + nsString outString; 1.195 + 1.196 + // per character look for the entity 1.197 + uint32_t len = NS_strlen(inString); 1.198 + for (uint32_t i = 0; i < len; i++) { 1.199 + nsAutoString key(NS_LITERAL_STRING("entity.")); 1.200 + if (NS_IS_HIGH_SURROGATE(inString[i]) && 1.201 + i + 2 < len && 1.202 + NS_IS_LOW_SURROGATE(inString[i + 1])) { 1.203 + key.AppendInt(SURROGATE_TO_UCS4(inString[i], inString[i+1]), 10); 1.204 + ++i; 1.205 + } 1.206 + else { 1.207 + key.AppendInt(inString[i],10); 1.208 + } 1.209 + 1.210 + nsXPIDLString value; 1.211 + const char16_t *entity = nullptr; 1.212 + 1.213 + for (uint32_t mask = 1, mask2 = 0xFFFFFFFFL; (0!=(entityVersion & mask2)); mask<<=1, mask2<<=1) { 1.214 + if (0 == (entityVersion & mask)) 1.215 + continue; 1.216 + nsIStringBundle* entities = GetVersionBundleInstance(entityVersion & mask); 1.217 + NS_ASSERTION(entities, "Cannot get the property file"); 1.218 + 1.219 + if (!entities) 1.220 + continue; 1.221 + 1.222 + nsresult rv = entities->GetStringFromName(key.get(), 1.223 + getter_Copies(value)); 1.224 + if (NS_SUCCEEDED(rv)) { 1.225 + entity = value.get(); 1.226 + break; 1.227 + } 1.228 + } 1.229 + if (entity) { 1.230 + outString.Append(entity); 1.231 + } 1.232 + else { 1.233 + outString.Append(&inString[i], 1); 1.234 + } 1.235 + } 1.236 + 1.237 + *_retval = ToNewUnicode(outString); 1.238 + if (!*_retval) 1.239 + return NS_ERROR_OUT_OF_MEMORY; 1.240 + 1.241 + return NS_OK; 1.242 +}